为什么C#编译器没有捕获InvalidCastException

Jer*_*ins 10 .net c# compiler-construction compilation exception

可能重复:
编译时和运行时转换c#

据我所知,以下代码将始终编译,并且还会在运行时始终通过抛出一个失败InvalidCastException.

例:


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
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是......

  1. 如果我的假设是关闭的,那么有人可以举例说明他们是如何关闭的吗?
  2. 如果我的假设是正确的,那么编译器为什么不警告这个错误呢?

Eri*_*ert 15

有几个原因可以解释为什么允许这种转换.

首先,正如人们在其他答案中所说的那样,演员操作符意味着"我知道的比你做得更多;我向你保证这个转换会成功,如果我错了,抛出异常并使进程崩溃".如果你对编译器撒谎,那么坏事就会发生; 你其实是没有做这样的保证,程序崩溃的结果.

现在,如果编译器可以告诉你说谎,那么它可以让你陷入困境.编译器不需要任意聪明地抓住你的谎言!确定Base类型的表达式永远不会是Derived 类型所需的流分析是复杂的; 比我们已经实现的逻辑要复杂得多,比如未分配的局部变量.我们有更好的方法来花费我们的时间和精力,而不是提高编译器在明显谎言中抓住你的能力.

因此,编译器通常只会考虑表达式的类型,而不是可能的值.仅从类型分析中就不可能知道转换是否会成功.它可能会成功,所以它是允许的.唯一不允许的强制转换是编译器知道的类型分析总是失败的.

其次,可以(Derived)(new Base())Derived是一个实现类型Base的类型,并且它在运行时不会失败.(Base)(new Base())在运行时也可能因无效的强制转换异常而失败!真实的事实!这些是非常罕见的情况,但它们可能的.

有关详细信息,请参阅有关此主题的文章:

http://blogs.msdn.com/b/ericlippert/archive/2007/04/16/chained-user-defined-explicit-conversions-in-c.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/04/18/chained-user-defined-explicit-conversions-in-c-part-two.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/04/20/chained-user-defined-explicit-conversions-in-c-part-three.aspx


McK*_*Kay 11

Post在某些情况下,A 可以被投射到Question.通过执行强制转换,你告诉编译器,"这将有效,我保证.如果没有,你可以抛出无效的强制转换异常."

例如,这段代码可以正常工作:

    Post p = new Question();
    Question q = (Question)p;
Run Code Online (Sandbox Code Playgroud)

演员明确表示你比编译器更了解这实际上是什么.您可能需要做一些喜欢asis关键字?


Pao*_*sco 8

问题的关键在于,p可能是一个Question问题Post.
考虑以下:

public class Post { }
public class Question : Post { }
public class Banana { }

static class Program {
    public static void Main(params string[] args) {
        Post p = new Question();
        Question q = (Question)p; // p IS a Question in this case
        Banana b = (Banana)p; // this does not compile
    }
}
Run Code Online (Sandbox Code Playgroud)


Ode*_*ded 6

当您进行显式转换时,您告诉编译器"我知道您不知道的事情".

你本质上是覆盖了编译器的正常逻辑 - p 可能Question(因此,编译器将编译),你告诉编译器你知道它(即使它不是,因此运行时异常).