指定基类类型时返回子类的C#类型转换

时间:2014-11-06 17:20:06

标签: c# type-conversion

当我运行以下内容时:

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

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

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

2 个答案:

答案 0 :(得分: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”而不管静态类型(运行时类型总是相同)来证明的。

但是,请注意使用“override”和“new”之间的区别:您将看到“parent.foo()”调用“ParentClass.foo”方法。这是因为“父”变量属于静态类型“ParentClass”类型,因此C#编译器发出IL指令以在“ParentClass”上调用该方法。您可以进一步看到“动态”类型引用仍然调用“InheritedClass.foo”,因为动态类型在运行时解析,并且这解析为实际的运行时类型“InheritedClass”。

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

答案 1 :(得分:1)

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

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

as可以"修改"一个对象,我认为你在说,例如,拳击不仅仅需要转换引用。

var o = 1 as object;

o是一个与整数1完全不同的对象。

重要的是要注意,在任何成功的as转换中GetType()仍然会返回 的一般行为的对象的原始类型>演员