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

本文关键字:类型转换 返回 子类 基类 类型 | 更新日期: 2023-09-27 18:29:22

当我运行以下程序时:

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

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

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

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

对象本身没有被修改,这就是为什么对象的类型在调试器中仍然显示为"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"answers"new"之间的区别:您将看到"parent.foo()"调用"ParentClass.foo"方法。这是因为"parent"变量属于静态类型"ParentClass"类型,因此C#编译器会发出IL指令来调用"ParentClass"上的方法。您可以进一步看到,"dynamic"类型引用仍然调用"InheritedClass.foo",因为动态类型在运行时解析,并且这解析为实际的运行时类型"Inherited Class"。

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

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

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

但是as可以"修改"一个对象,我想你是在说,例如,装箱不仅仅需要转换引用。

var o = 1 as object;

CCD_ 10是与整数CCD_ 11完全不同的对象。

值得注意的是,在任何成功的as转换中,GetType()仍将返回对象的原始类型,而不是强制转换运算符的一般行为。