让我们说我们在C#中有以下示例代码:
class BaseClass
{
public virtual void HelloWorld()
{
Console.WriteLine("Hello Tarik");
}
}
class DerivedClass : BaseClass
{
public override void HelloWorld()
{
base.HelloWorld();
}
}
class Program
{
static void Main(string[] args)
{
DerivedClass derived = new DerivedClass();
derived.HelloWorld();
}
}
Run Code Online (Sandbox Code Playgroud)
当我ildasmed以下代码:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 15 (0xf)
.maxstack 1
.locals init ([0] class EnumReflection.DerivedClass derived)
IL_0000: nop
IL_0001: newobj instance void EnumReflection.DerivedClass::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: callvirt instance void EnumReflection.BaseClass::HelloWorld()
IL_000d: nop
IL_000e: ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)
但是,csc.exe已转换derived.HelloWorld();- > callvirt instance void EnumReflection.BaseClass::HelloWorld().这是为什么?我没有在Main方法中的任何地方提到BaseClass .
而且如果它正在调用BaseClass::HelloWorld()那么我会期望call而不是callvirt因为它看起来直接调用BaseClass::HelloWorld()方法.
pho*_*oog 20
调用转到BaseClass :: HelloWorld,因为BaseClass是定义方法的类.虚拟分派在C#中的工作方式是在基类上调用该方法,并且虚拟分派系统负责确保调用方法的最派生覆盖.
Eric Lippert的答案非常有用:https://stackoverflow.com/a/5308369/385844
正如他关于这个主题的博客系列:http://blogs.msdn.com/b/ericlippert/archive/tags/virtual+dispatch/
你知道为什么这样实现吗?如果直接调用派生类ToString方法会发生什么?这种方式乍一看对我来说没什么意义......
它是以这种方式实现的,因为编译器不跟踪对象的运行时类型,只跟踪其引用的编译时类型.使用您发布的代码,很容易看到该调用将转到该方法的DerivedClass实现.但假设derived变量初始化如下:
Derived derived = GetDerived();
Run Code Online (Sandbox Code Playgroud)
它可能会GetDerived()返回一个实例StillMoreDerived.如果StillMoreDerived(或继承链之间Derived和之间的任何类StillMoreDerived)重写该方法,则调用Derived该方法的实现将是不正确的.
要找到变量可以通过静态分析保持的所有可能值,就可以解决暂停问题.使用.NET程序集时,问题更严重,因为程序集可能不是一个完整的程序.因此,编译器可以合理地证明derived不包含对更多派生对象(或空引用)的引用的情况的数量将很小.
添加这个逻辑需要花多少钱才能发出call而不是callvirt指令呢?毫无疑问,成本将远远高于所获得的小额效益.
考虑这个问题的方法是虚方法定义一个"槽",您可以在运行时将方法放入其中.当我们发出一个callvirt指令时,我们说"在运行时,看看这个插槽中的内容并调用它".
槽由有关声明虚方法的类型的方法信息标识,而不是覆盖它的类型.
向派生方法发出callvirt是完全合法的; 运行时会意识到派生方法与基本方法是相同的槽,结果将完全相同.但是从来没有任何理由这样做.如果我们通过识别声明该槽的类型来识别槽,则更清楚.
| 归档时间: |
|
| 查看次数: |
692 次 |
| 最近记录: |