我有两个班级
public class A
{
public A()
{
}
}
public class B:A
{
public B()
{
}
}
以及Main中的代码如下
A oa = new B();
B ob = new A();
此处第1行成功编译,第2行显示类型转换错误。为什么会这样。调用new B()
和new A()
时会发生什么?
答案 0 :(得分:7)
您已声明了B
类型的变量,然后尝试为其指定类型A
的值。您已将B
定义为某种A
,但这并不意味着所有A
都是B
。
这样想:
class Animal { }
class Dog : Animal { }
class Cat : Animal { }
你可以Animal rex = new Dog()
,因为所有的狗都是动物,但不是Dog fido = new Animal()
,因为并非所有的动物都是狗。
答案 1 :(得分:2)
新B()和 新的A()被调用?
new A()
在堆上构造类型为A
的对象,并返回对它的引用。
new B()
在堆上构造类型为B
的对象,并返回对它的引用。
这里第1行成功编译 第2行显示类型转换 错误。为什么会这样。
从B
子类A
开始,它对类型A
的引用有效,以引用运行时类型B
的对象。毕竟,B
只是A
的“特殊情况”。
然而,相反的情况并非如此,因为并非所有A
都可以被视为B
。
虽然这是由C#的安全类型系统严格执行的,即使没有“真正的”不兼容性,但这种限制的原因是很自然的。例如,想象一下,B
声明了一个属性public int Foo {get; set;}
。
您如何期望这样做:
B ob = new A();
ob.Foo = 5;
这显然是不合逻辑的:引用引用的真实对象没有这样的属性。因此,编译器禁止这样的结构。
现在假设您将代码更改为:
B b = (B)new A();
在这里,您告诉编译器,在运行时创建的对象可以分配给类型为B
的引用。这将编译正常,但由于断言明显不正确,将抛出运行时InvalidCastException
。
总结一下,C#的类型系统(如果你忽略dynamic
和一些特殊情况)是静态和安全:你将无法成功处理A
的具体实例,就好像它是B
类型一样。