Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the C# compiler catch an InvalidCastException [duplicate]

Possible Duplicate:
Compile-time and runtime casting c#

As I understand it, the following code will always compile, and will additionally always fail at run-time by throwing an InvalidCastException.

Example:


public class Post { }
public class Question : Post { }
public class Answer : Post 
{
    public void Fail()
    {
        Post p = new Post();
        Question q = (Question)p; // This will throw an InvalidCastException
    }
}

My questions are...

  1. If my assumptions are off, then can someone provide an example demonstrating how they're off?
  2. If my assumptions are correct, then why doesn't the compiler warn against this error?
like image 778
Jeremy Wiggins Avatar asked Nov 17 '11 15:11

Jeremy Wiggins


2 Answers

There are a couple of reasons why this conversion is allowed.

First, as people have said in other answers, the cast operator means "I know more than you do; I guarantee you that this conversion will succeed and if I am wrong, throw an exception and crash the process". If you are lying to the compiler, bad things are going to happen; you in fact are not making that guarantee, and the program is crashing as a result.

Now, if the compiler can tell that you are lying to it, then it can catch you in the lie. The compiler is not required to be arbitrarily clever in catching you in your lies to it! The flow analysis needed to determine that an expression of type Base is never going to be of type Derived is complex; considerably more complex than the logic we already implement to catch things like unassigned local variables. We have better ways to spend our time and effort than in improving the compiler's ability to catch you out in obvious lies.

The compiler therefore typically reasons only about types of expressions, not about possible values. Solely from the type analysis it is impossible to know whether or not the conversion will succeed. It might succeed, and so it is allowed. The only casts that are disallowed are the ones that the compiler knows will always fail from the type analysis.

Second, it is possible to say (Derived)(new Base()) where Derived is a type that implements type Base and have it not fail at runtime. It is also possible for (Base)(new Base()) to fail with an invalid cast exception at runtime! True facts! These are extraordinarily rare situations but they are possible.

For more details, see my articles on the subject:

  • Chained user-defined explicit conversions in C#
  • Chained user-defined explicit conversions in C#, Part Two
  • Chained user-defined explicit conversions in C#, Part Three
like image 92
Eric Lippert Avatar answered Oct 06 '22 00:10

Eric Lippert


A Post could, under some cases, be cast to a Question. By performing the cast, you're telling the compiler, "This will work, I promise. If it doesn't you're allowed to throw an invalid cast exception."

For example, this code would work fine:

    Post p = new Question();
    Question q = (Question)p;

A cast is expressly stating that you know better than the compiler what this actually is. You may want to do something like the as or is keywords?

like image 28
McKay Avatar answered Oct 06 '22 01:10

McKay