有关C#中对象引用类型转换的问题?

时间:2010-11-02 23:47:01

标签: c# object types reference casting

我有一个关于对象类型转换的问题。 假设我们有:

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的所有成员?

由于

2 个答案:

答案 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位引用。对于值类型对象,在分配期间会复制个别成员(字段)