我有一个关于对象类型转换的问题。 假设我们有:
A a = new A();
Object o = a;
据我所知,背后发生的事情是编译器会复制a的地址并存储在o变量的内存区域中。然后,我们可以说a和o引用同一个对象。
如果我们这样做:
String s = "abc";
int a = (int)s;
然后我明白编译器不能将字符串值复制到int内存区域。
但如果我们有:
A a = new A();
B b = (B)a;
这在编译时可能没问题。但是,可能会发生运行时错误,例如“无法投射......”。
所以,我不明白在内存中实际发生的事情会导致无法执行上面的转换。它只是将a的地址复制到b的内存区域吗?如果是这样,为什么不可能呢? 或者它会复制A的所有成员来替换B的所有成员?
由于
答案 0 :(得分:6)
编译器执行静态类型检查意味着如果A和B不属于同一继承层次结构,则不允许在两者之间发生强制转换。
考虑一下,如果它们不属于同一层次结构,即使编译器允许您将A的对象转换为B类型,因为A不从B或其继承者继承,您可能想要调用其中一个方法对于铸造对象的类型B,它将在运行时失败。
class A { }
class B {
void Foo() { }
}
A a = new A();
B b = (B)a; // Compiler Error
// Hypothetically, if above was allowed, the below would ALWAYS fail at runtime
// Since there is no way the object "b" can handle this call.
b.Foo();
这里有一个有趣的观点,如果B是一个接口,编译器会让强制转换发生,即使它们不属于同一个继承树:
class A { }
interface B {
void Foo();
}
A a = new A();
B b = (B)a; // Compiler lets this happens
// Even though A does not implement B, but still one of the base classes of A
// might have implement B and A inherits that so it might be able to handle this
b.Foo();
之所以这样,是因为A可能来自不同的层次结构树,但仍有可能A或其中一个基类实现了B,因此您可能会有一个点,而编译器会允许它。
答案 1 :(得分:0)
正如Morteza所解释的那样,C#编译器将进行静态类型检查以确定是否可以进行强制转换。
至于运行时会发生什么,您可能需要查看生成的IL以获得更好的想法。对于引用类型,您的强制转换可能会成为IL castclass
指令。这会导致运行时检查实际的对象类型以查看强制转换是否有效。如果是,则将引用(指向对象的32位或64位指针)隐含在变量赋值中,如预期的那样。如果不是,则抛出InvalidCastException。
对于引用类型对象,永远不会复制各个成员。仅复制32/64位引用。对于值类型对象,在分配期间会复制个别成员(字段)。