使用泛型强制转换调用阴影方法
本文关键字:调用 阴影 方法 转换 泛型 | 更新日期: 2023-09-27 18:17:23
我正在尝试编写一个方法,将对象转换为泛型类型以执行特定的影子方法。这是我的测试代码:
class Program
{
static void Main(string[] args)
{
hello2 h2 = new hello2();
test(h2);
Console.ReadLine();
}
static void test(hello h)
{
h.write2<hello2>();
}
}
class hello
{
public virtual void write()
{
Console.WriteLine("hello");
}
public void write2<T>() where T : hello
{
T h2 = (T)this;
hello2 h21 = (hello2)this;
h2.write();
h21.write();
}
}
class hello2 : hello
{
public new void write()
{
Console.WriteLine("hello2");
}
}
My Console Output is:
你好hello2
我调试了它,检查了所有内容,但没有发现错误。在这两种情况下,输出都应该是hello2。我是不是漏掉了什么明显的东西?或者这只是不起作用?
您缺少的是在hello
的编译时而不是在使用write2
时选择调用的方法。所以在编译时,编译器只知道T
是hello
类型或其他派生类,所以它选择阴影方法,因为这是它在编译时唯一知道的方法。
这样想,将每个T
替换为:
右侧的任何内容。这是编译器看到的信息,并使用该信息做出选择。
//What the complier sees when you compile even if you pass in hello2 as T.
public void write2<T>() where T : hello
{
hello h2 = (hello)this;
hello2 h21 = (hello2)this;
h2.write();
h21.write();
}
当方法声明为virtual
时,将被调用的方法的解析延迟到运行时,并取决于运行时对象的类型。来自c#规范:
在c#规范中,虚方法的解析如下:在虚方法调用中,实例的运行时类型调用发生的地方决定了实际的方法
对于在类中声明或继承的每个虚方法,有存在该方法的最派生的实现这类。虚方法M的最派生实现
- 如果R包含M的引入虚声明,则这是M的最派生的实现。
否则,如果R包含 M的重写,则这是M的最派生实现。- 否则,M相对于R的最派生实现与M相对于的最派生实现相同r的直接基类。
所以当你写:
T h2 = (T)this;
h2.write();
编译器知道h2是hello
或派生类型,而write
是一个虚方法,其解析将延迟到运行时。
在运行时,即使类的类型是hello2
,解析也会选择类hello
中的方法。这是因为hello2
类中的write
方法不包含override
关键字,因此在解析虚拟调用时不会考虑它。(因此,在hello2
上调用write的唯一方法是确保编译器知道实例的类型是hello2
)
这也是为什么如果你在hello2
上用override而不是new声明write,那么在这两种情况下,同一个程序的输出将是hello2。
编辑
似乎您想编写一个能够在hello
或hello2
中调用write
的方法,即使该方法已在hello2
中使用new操作符声明。
您可以编写一个使用dynamic
变量的扩展方法。例如,创建以下扩展方法:
public static class HelloExtensions
{
public static void writeDynamic<T>(this T h) where T: hello
{
dynamic hdynamic = h;
hdynamic.write();
}
}
然后,您可以编写以下测试程序,该程序将该扩展方法与原始类一起使用:
class Program
{
static void Main(string[] args)
{
testDynamic(new hello());
testDynamic(new hello2());
Console.ReadLine();
}
static void testDynamic(hello h)
{
h.writeDynamic();
}
}
输出将是:
hello
hello2
您在方法中使用的write
方法
public void write2<T>() where T : hello {
T h2 = (T)this;
hello2 h21 = (hello2)this;
h2.write(); // <--- this one
h21.write();
}
是在hello
类型上定义的write
方法(使用智能感知检查它)。因此,当您实际调用类型为hello2
的特定T类型的方法时,如果类型为hello
,它仍然是write
方法。由于您使用new操作符在类型hello2
中定义write
方法,因此不会调用该方法。
如果在方法中显式地将类型转换为hello2
,则只能使用类型为hello2
的方法,而不能使用类型未知的T
。