繁体   English   中英

在泛型类中使用Activator.CreateInstance结合方法上的“ new”修饰符

[英]Using Activator.CreateInstance in generic class combined with “new” modifier on method

我有一个继承自BaseClass的类(DerivedClass)。 在DerivedClass中,我在方法(SayHello())上使用“ new”修饰符,因为我想更改签名-我想添加一个返回值。
我也有一个通用类。 提供给泛型类的类型应为“ BaseClass”类型(在我的情况下为BaseClass或DerivedClass)。

如果我使用Activator.CreateInstance <T>()获取通用类型的新实例,然后调用我的方法,则始终会调用BaseClass上的方法。 将DerivedClass上的SayHello方法设置为通用类型时,为什么不调用它?

我制作了一个简单的控制台应用程序来说明:

namespace TestApp
{
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var gc = new GenericClass<DerivedClass>();
            gc.Run();
        }
    }

    public class BaseClass
    {
        public void SayHello()
        {
            Console.WriteLine("Hello!");
        }
    }

    public class DerivedClass : BaseClass
    {
        new public int SayHello()
        {
            Console.WriteLine("Hello returning int!");
            return 1;
        }
    }

    public class GenericClass<T> where T : BaseClass
    {
        public void Run()
        {
            var bc = new BaseClass();
            bc.SayHello(); // Hello!

            var dc = new DerivedClass();
            dc.SayHello(); // Hello returning int!

            var dc2 = Activator.CreateInstance<T>();
            dc2.SayHello(); // Hello!
            Console.WriteLine(dc2.GetType()); // TestApp.DerivedClass

            Console.Read();
        }
    }
}

因为您没有覆盖该方法,所以将其隐藏起来。 如果您将方法设为虚拟方法,而是对其进行覆盖,那么您将获得期望的结果。

GenericClassRun方法不知道对象的运行时类型,它仅知道它是从BaseClass派生的类型,因此它只能在编译时绑定BaseClass中该方法的实现。 由于尚未通过将方法设置为virtual来启用虚拟调度,因此无法知道派生类型的方法。

因为组合:

public class GenericClass<T> where T : BaseClass

和:

new public int SayHello()

告诉编译器,在编译时T将为BaseClass类型,并且方法重载匹配发生在编译时,而不是在运行时。 因此,您的运行时类型不同的事实实际上并没有在这里发挥作用,因为它是使用new修饰符“运行”的,而不是通过覆盖虚拟方法分派(就像返回类型一样)您的两个方法调用都相同( void )。

您会在生成的IL中看到它:

GenericClass`1.Run:

IL_001B:  call        01 00 00 2B 
IL_0020:  stloc.2     // dc2
IL_0021:  ldloca.s    02 // dc2
IL_0023:  constrained. 02 00 00 1B 
IL_0029:  callvirt    UserQuery+BaseClass.SayHello

您可以使用动态关键字:

 dynamic dc2 = Activator.CreateInstance<T>(); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM