在泛型类中使用Activator.CreateInstance并结合" new"方法的修饰语

时间:2015-05-27 14:34:18

标签: c# generics inheritance activator

我有一个继承自BaseClass的类(DerivedClass)。 在DerivedClass中,我使用" new"一个方法的修饰符(SayHello()),因为我想改变签名 - 我想添加一个返回值。
我也有一个通用类。提供给泛型类的类型应为" 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();
        }
    }
}

3 个答案:

答案 0 :(得分:2)

因为您没有覆盖该方法,所以您要将其隐藏起来。如果您将方法设为虚拟,并改为覆盖它,那么您将获得您期望的结果。

Run的{​​{1}}方法不知道对象的运行时类型,它只知道它是从GenericClass派生的类型,所以它只能在编译时绑定BaseClass中方法的实现。由于您尚未通过制作方法BaseClass启用虚拟调度,因此无法了解派生类型的方法。

答案 1 :(得分:1)

因为组合:

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

答案 2 :(得分:0)

您可以使用动态关键字:

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