我正在尝试编写一个将对象强制转换为泛型类型以执行特定阴影方法的方法。这是我的测试代码:
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");
}
}
我的控制台输出是:
您好
hello2
我调试了它,检查了所有内容并找不到错误。在两种情况下,输出应为hello2。我错过了一些明显的东西吗?或者这只是不起作用?
答案 0 :(得分:3)
您缺少的是调用的方法是在hello
的编译时选择的,而不是write2
的使用。所以在编译时,所有编译器都知道T
是类型hello
或其他一些派生类,所以它选择了shadowed方法,因为这是它在编译时知道的唯一方法。
以这种方式思考,用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();
}
答案 1 :(得分:3)
当方法声明为virtual
时,将调用的方法的分辨率将延迟到运行时,并取决于运行时对象的类型。来自C# spec:
在虚方法调用中,实例的运行时类型 调用发生的位置决定了实际的方法 要调用的实现。
从C# spec开始,虚拟方法的解析如下:
对于在类中声明或继承的每个虚方法,都存在 存在关于方法的最派生的实现 那个班。虚拟方法M的最多派生实现 对R类的尊重如下确定:
- 如果R包含M的引入虚拟声明,那么这是M的最多派生实现。
- 否则,如果R包含覆盖M ,则这是M的派生最多的实现。
- 否则,关于R的M的最派生实现与关于的M的最派生实现相同 R的直接基类。
所以当你写:
T h2 = (T)this;
h2.write();
编译器知道h2的类型为hello
或派生,而write
是一个虚拟方法,其分辨率将推迟到运行时。
在运行时,分辨率将选择类hello
中的方法,即使该类的类型为hello2
。这是因为类write
中的hello2
方法不包含override
关键字,在解析虚拟调用时不会考虑。 (因此,在hello2
上调用write的唯一方法是确保编译器知道实例的类型为hello2
}
这也是为什么如果您使用覆盖而不是新在hello2
上声明写入,则同一程序的输出将为 hello2 两种情况。
修改强>
您似乎想编写一种能够在write
或hello
中调用hello2
的方法,即使该方法已在hello2
中使用新运算符声明
您可以编写使用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
答案 2 :(得分:0)
您在方法中使用的write
方法
public void write2<T>() where T : hello {
T h2 = (T)this;
hello2 h21 = (hello2)this;
h2.write(); // <--- this one
h21.write();
}
是在write
类型上定义的hello
方法(使用intellisense检查)。因此,当您实际使用类型hello2
的特定T类型调用方法时,如果键入write
,它仍然是hello
方法。由于您使用new运算符在类型write
中定义hello2
方法,因此不会调用此方法。
如果您明确地将其转换为在方法中键入hello2
,而不是尚未知道类型{{},则只能使用hello2
类型的方法1}}。