使用催化剂.在泛型类中创建实例并结合"new"方法上的修饰符
本文关键字:quot new 方法 结合 催化剂 泛型类 实例 创建 | 更新日期: 2023-09-27 17:50:56
我有一个类(DerivedClass)继承自BaseClass。在DerivedClass中,我在方法(SayHello())上使用了"new"修饰符,因为我想更改签名-我想添加一个返回值。
我还有一个泛型类。提供给泛型类的类型应该是"BaseClass"类型(在我的例子中是BaseClass或DerivedClass)。
如果我使用Activator.CreateInstance
我做了一个简单的控制台应用程序来说明:
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();
}
}
}
因为您没有重写该方法,所以您是在遮蔽它。如果你把这个方法设为虚方法,然后重写它,那么你就会得到你想要的结果。
GenericClass
的Run
方法不知道对象的运行时类型,它只知道它是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>();