C# `CallVirt`和`New`关键字
这个问题与 在我的例子中,我使用的是C# `CallVirt`和`New`关键字,c#,.net,oop,clr,C#,.net,Oop,Clr,这个问题与 在我的例子中,我使用的是callvirt指令,而不是call class BaseClass { public void Write() { Method(); } protected virtual void Method() { Console.WriteLine("Base - Method"); } }
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
写入方法的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
。为什么调用基类方法?当搜索方法时,callvirt
是否查找特定的override
标志 因为你没有覆盖它。将new
更改为override
,它将按照您讨论的方式运行(您还必须将可访问性更改为protected
,否则它将无法编译)new
创建一个恰好共享名称的不相关的方法-它不是基类中同名的其他方法的多态树的一部分
您可能会问:“为什么这个调用不完全区分名称()
?”
答案是一样的:
完全不同的名称
与名为方法
的虚拟
(多态)方法没有任何关系。嗯,new void Method()
-这就是new
在这里的意思。因为这正是new应该如何工作的。
New意味着您的新方法与基类中同名的方法没有任何共同之处。
这与使用另一个名称在派生类方法中创建相同,只是使用了相同的名称。
也就是说,基类方法write不会尝试调用新方法,因为它不是基类中方法的新版本,它只是该类的另一个成员。我标记了
DerivedClass.method
以覆盖基类方法。在IL中,我看到.methodfamily隐藏虚拟实例void method()cil managed
。这是否意味着callvirt
在查找派生方法时实际搜索virtual
关键字?使用new
关键字IL是.method private hidebysig instance void method()cil managed
——这是一个普通的方法。@nikita:正如所有其他人所说,“new”创建了一个不相关的方法,恰好具有相同的名称,与“override”相反。因此,请看:private new void Method()
。这种方法是正常的。它不是虚拟的,只是私有void Method()
,因此编译器发出了一个普通方法。如果您编写了private new virtual void Method()
,那么它将创建一个虚拟方法。新的、虚拟的、与基础虚拟无关的。请注意,当您重写时,创建的方法显然是自动虚拟的。但是,新技术并不意味着任何形式的“虚拟”。
class BaseClass
{
public void Write()
{
Method();
}
protected virtual void Method()
{
Console.WriteLine("Base - Method");
}
}
class DerivedClass : BaseClass
{
private void CompletelyDifferentName()
{
Console.WriteLine("Derived - Method");
}
}