2014-11-06 117 views
0

的类型时,当我运行以下返回子类:C#类型转换指定基类

ParentClass foo = serializer.Deserialize(xmlReader) as ParentClass;

xmlReader加载的XML文档是ParentClass继承的类型。在调试器中检查时,foo显示为继承类的实例,而不是父类。当然,继承类也是类型ParentClass,但为什么as关键字具有这种行为?为什么C#不去掉所有不需要转换为ParentClass的对象信息。

这不是问题,但或多或​​少是出于好奇的问题。

+2

如果它是一个ChildClass,那么你将在调试器中看到,你只是将它转换成一个'ParentClass'而不是转换它,它仍然是一个'ChildClass'并且可以退回。 – 2014-11-06 17:23:01

+0

因为它实际上是在内存中键入'ChildClass'的引用。演员阵容不会改变这一点。 – 2014-11-06 17:28:31

+0

所以“as”实际上不会以任何方式修改对象?它只是验证给定一个对象的引用,继承结构是兼容的? – Tim 2014-11-06 17:34:21

回答

1

对象本身没有被修改,这就是为什么对象的类型仍然在调试器中显示为“ParentClass”的原因。

考虑下面的例子,我认为这是例证性的。你认为在这里输出到控制台是什么?

class Program 
{ 
    public class ParentClass 
    { 
     public virtual void foo() 
     { 
      Console.WriteLine("parent.foo"); 
     } 

     public virtual void bar() 
     { 
      Console.WriteLine("parent.bar"); 
     } 
    } 

    public class InheritedClass : ParentClass 
    { 
     public new void foo() 
     { 
      Console.WriteLine("inherited.foo"); 
     } 

     public override void bar() 
     { 
      Console.WriteLine("inherited.bar"); 
     } 
    } 

    static void Main(string[] args) 
    { 
     var inherited = new InheritedClass(); 
     var parent = inherited as ParentClass; 
     var d = parent as dynamic; 

     parent.foo(); 
     inherited.foo(); 
     d.foo(); 

     parent.bar(); 
     inherited.bar(); 
     d.bar(); 

     Console.Read(); 
    } 
} 

只有一个对象被创建,然后它会创建两个引用:一个继承的静态类型,和一个与“动态”类型。所有引用引用同一个对象的情况都可以通过调用“bar”调用“InheritedClass.bar”来实现,而不管静态类型如何(运行时类型始终相同)。但是,请注意使用“覆盖”和“新”之间的区别:您将看到“parent.foo()”调用“ParentClass.foo”方法。这是因为“父”变量是静态类型“ParentClass”类型,所以C#编译器发出IL指令来调用“ParentClass”上的方法。您可以进一步看到“动态”类型引用仍然调用“InheritedClass.foo”,因为动态类型在运行时解析,并且这解析为实际运行时类型,即“InheritedClass”。

编辑 @InBetween有一个重要的区别,我没有考虑。在从值类型转换为引用类型(反之亦然)的情况下,新对象实际创建,因为新内存必须分别在堆或堆栈上分配(“装箱”过程)。当然,部分由于这个原因,struct和其他值类型不支持虚拟方法。

+0

谢谢。这绝对清除了我的问题。 – Tim 2014-11-06 18:48:33

1

as只能执行参考转换,可空转换和装箱转换。它不会执行任何其他类型的转换,如用户定义的转换。

在你的情况下,它执行兼容的参考转换;对象保持不变,你只是改变参考。

但是as可以在某种意义上“修改”一个对象,例如,我认为你说的时候,例如,装箱不仅仅是简单地转换引用。

var o = 1 as object; 

o是一个产品总数不同的对象比整数1

重要的是要注意,虽然在任何成功的as转换GetType()仍然会返回原来的类型,是转换运算符的一般行为的对象是很重要的。

+0

+1,关于拳击/拆箱非常好。 – McGarnagle 2014-11-06 18:06:03

+0

我看不出如何考虑装箱修改。 – usr 2014-11-07 15:18:33

+0

@usr:引用转换更改引用的* type *,但它指向的对象保持不变。当装箱*值类型*你正在包装一个'System.Object'内的值并存储它*其他地方*(托管堆,虽然这是障碍sepcific);这意味着你有一个完全不同的对象的参考。 – InBetween 2014-11-07 15:22:46