gpt4 book ai didi

.net - callvirt 在底层是如何工作的?

转载 作者:行者123 更新时间:2023-12-04 17:40:51 25 4
gpt4 key购买 nike

我试图了解 CLR 如何实现引用类型和多态性。我提到了 Don Box 的 Essential .Net Vol 1,它对校准大部分内容有很大帮助。但是当我尝试使用一些 IL 代码以更好地理解时,我被以下问题卡住/困惑。

我会尽量解释这个问题。
考虑以下代码

class Base
{
public void m()
{
Console.WriteLine("Base.m");
}
}
class Derived : Base
{
public void m()
{
Console.WriteLine("Derived.m");
}
}

现在考虑一个简单的控制台应用程序,其中包含如下所示的主要方法的 IL。
我手动调整了编译器创建的 IL 以理解并使用 ILAsm.exe 再次组装
.class private auto ansi beforefieldinit Console1.Program
extends [mscorlib]System.Object
{
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 44 (0x2c)
.maxstack 1
.locals init ([0] class Console1.Base d)
nop
newobj instance void Console1.Base::.ctor()
stloc.0
ldloc.0
callvirt instance void Console1.Derived::m()
nop
call string [mscorlib]System.Console::ReadLine()
pop
ret
} // end of method Program::Main
} // end of class Console1.Program

我期望这段代码不会运行,因为对象引用指向 Base 的对象,并且基对象的方法表不可能有一个条目,用于在派生类中定义的方法 m()。

但神奇的是,这段代码执行了 Derived.m()!!

所以,在上面的代码中有两个我不明白的问题:
  • 下面 IL 代码中指定的 Type 有什么意义?我试图通过将其更改为不同类型(例如 System.Exception!!)来进行试验,并且没有报告任何错误。为什么??

    .locals init ([0] 类 Console1.Base d)
  • callvirt 究竟是如何工作的?调用是如何路由到 Derived.m() 的?

  • 提前致谢!!

    问候,
    阿杰

    最佳答案

    我的猜测是抖动意识到 Derived.m不是虚拟的,因此永远不能指向其他任何地方。所以callvirt减少为空检查和调用,而不是通过 v-table 调用。

    尝试制作 Derived.m虚拟的。我打赌它会抛出。

    C# 编译器发出 callvirt即使在调用非虚拟方法时也无法证明的指令 this!=null所以它得到一个空检查。在这种情况下,抖动足够智能,可以用具有固定地址(甚至内联)的普通调用替换虚拟调用。

    您应该检查您的代码是否可验证。我认为不是。

    关于.net - callvirt 在底层是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4292409/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com