使用催化剂.在泛型类中创建实例并结合"new"方法上的修饰符

本文关键字:quot new 方法 结合 催化剂 泛型类 实例 创建 | 更新日期: 2023-09-27 17:50:56

我有一个类(DerivedClass)继承自BaseClass。在DerivedClass中,我在方法(SayHello())上使用了"new"修饰符,因为我想更改签名-我想添加一个返回值。
我还有一个泛型类。提供给泛型类的类型应该是"BaseClass"类型(在我的例子中是BaseClass或DerivedClass)。

如果我使用Activator.CreateInstance()来获得我的泛型类型的新实例,然后调用我的方法,那么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();
        }
    }
}

使用催化剂.在泛型类中创建实例并结合"new"方法上的修饰符

因为您没有重写该方法,所以您是在遮蔽它。如果你把这个方法设为虚方法,然后重写它,那么你就会得到你想要的结果。

GenericClassRun方法不知道对象的运行时类型,它只知道它是BaseClass派生的类型,因此它只能在编译时绑定BaseClass中该方法的实现。由于您没有通过创建方法virtual来启用虚拟分派,因此它无法知道派生类型的方法。

因为:

public class GenericClass<T> where T : BaseClass

:

new public int SayHello()

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

在生成的IL中可以看到:

GenericClass"1。运行:

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>();