在我的情况下,我使用的是callvirt
指令,而不是call
class BaseClass
{
public void Write()
{
Method();
}
protected virtual void Method()
{
Console.WriteLine("Base - Method");
}
}
class DerivedClass : BaseClass
{
private new void Method()
{
Console.WriteLine("Derived - Method");
}
}
static void Main(string[] args)
{
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
dc.Write();
bcdc.Write();
Console.ReadKey(true);
}
输出:
Base - Method
Base - Method
Write
方法的IL代码:
.method public hidebysig instance void Write() cil managed
{
// Code size 9 (0x9)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance void Private_override.Program/BaseClass::Method()
IL_0007: nop
IL_0008: ret
} // end of method BaseClass::Write
我在这里不明白为什么调用Base
方法。
这里CLR使用callvirt
指令,这意味着它将查找调用变量类型,因为类型为DerivedClass
而DerivedClass
隐藏BaseClass.Method
,那么应该只有在堆中的DerivedClass的MethodTable中为DerivedClass.Method
。为什么调用BaseClass.Method
? callvirt
在搜索方法时会查找特定的override
标记吗?
答案 0 :(得分:7)
因为你没有override
它。将new
更改为override
,它会按照您的讨论行事(您必须将可访问性更改为protected
,否则将无法编译)。 new
创建一个无关的方法,恰好共享一个名称 - 它不是基类中其他同名方法的多态树的一部分。
您不妨问:“为什么不拨打CompletelyDifferentName()
?”
class BaseClass
{
public void Write()
{
Method();
}
protected virtual void Method()
{
Console.WriteLine("Base - Method");
}
}
class DerivedClass : BaseClass
{
private void CompletelyDifferentName()
{
Console.WriteLine("Derived - Method");
}
}
答案是一样的:CompletelyDifferentName
与名为virtual
的{{1}}(多态)方法没有任何关系。好吧,Method
也没有 - 这就是new void Method()
的含义。
答案 1 :(得分:1)
因为这正是新的应该如何运作。 New表示新方法与基类中具有相同名称的方法没有任何共同之处。 它与使用其他名称在派生类方法中创建相同,只是使用相同的名称。 即基类方法write不会尝试调用new方法,因为它不是基类中Method的新版本,它只是该类的另一个成员。