我想知道为什么在编译时会检查C#中的某些强制转换,而在其他情况下,责任会转储到CLR上。如上所述都是不正确的,但以不同的方式处理。
class Base { }
class Derived : Base { }
class Other { }
static void Main(string[] args)
{
Derived d = (Derived)new Base(); //Runtime InvalidCastException
Derived d = (Derived)new Other(); //Compile-time Cannot convert type...
}
在阅读“C#深度”的同时,我找到了有关此主题的信息,其中autor说:
“如果编译器发现该转换实际上不可能工作,它将触发编译错误 - 如果理论上允许但在执行时实际上不正确,则CLR将抛出异常。”
“理论上”是否意味着通过继承层次结构(对象之间的另一个亲和力?)连接,还是编译器的内部业务?
答案 0 :(得分:22)
编译器仅考虑静态类型。运行时检查动态(运行时)类型。 看看你的例子:
Other x = new Other();
Derived d = (Derived)x;
x
的静态类型为Other
。这与Derived
无关,因此转换在编译时失败。
Base x = new Base();
Derived d = (Derived)x;
x
的静态类型现在为Base
。 Base
类型的某些内容可能具有动态类型Derived
,因此这是一个向下转发。通常,编译器无法从x
的静态类型中了解Base
的某些其他子类的运行时类型是Derived
,Base
。因此决定是否允许强制转换是留给运行时的。
答案 1 :(得分:1)
如果您的变量属于Base
类型,理论上可以由Derived
构造函数构造,因此实际上是Derived
类型的变量。在编译时,编译器不会费心去试图弄清楚在每个特定情况下是否可以进行这种向下转换(将Base
类型的变量表示为Derived
类型的实体)。
您的样本很简单 - 您创建一个新类并立即投射它。但是,如果你从其他地方获得Base
该怎么办?例如,某些方法调用?编译器无法“猜测”您的方法将返回什么,因此不会抛出错误。
当您转换Other
时,编译器发现Other
实际上不可能Derived
并抛出异常。