我试图了解CLR如何实现引用类型和多态.我已经提到了Don Box的Essential .Net第1卷,这对于大部分内容都是很有帮助的.但是当我尝试使用一些IL代码来更好地理解时,我对以下问题感到困惑/困惑.
我会尽力解释这个问题.请考虑以下代码
class Base
{
public void m()
{
Console.WriteLine("Base.m");
}
}
class Derived : Base
{
public void m()
{
Console.WriteLine("Derived.m");
}
}
Run Code Online (Sandbox Code Playgroud)
现在考虑一个简单的控制台应用程序,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
Run Code Online (Sandbox Code Playgroud)
我期望这段代码不要运行,因为对象引用指向Base的对象,并且基础对象的方法表无法为Derived类中定义的方法m()创建条目.
但神奇地这个代码执行Derived.m()!!
所以,在上面的代码中有两个我不理解的问题:
以下IL代码中指定的Type的含义是什么?我试图通过将其更改为不同的类型(例如System.Exception !!)进行实验,并且没有报告错误.为什么??
.locals init([0]类Console1.Base d)
提前致谢!!
此致,Ajay
我的猜测是抖动意识到这Derived.m不是虚拟的,因此永远不会指向其他任何地方.所以callvirt减少到空检查和调用而不是通过v表调用.
尝试制作Derived.m虚拟.我打赌它会扔掉.
callvirt即使在调用非虚方法时,C#编译器也会发出指令,如果它无法证明这样,this!=null那么它会得到一个空检查.在这种情况下,抖动足够智能,可以通过固定地址(甚至内联它)的正常呼叫来替换虚拟呼叫.
你应该检查你的代码是否可以验证.我认为不是.
| 归档时间: |
|
| 查看次数: |
652 次 |
| 最近记录: |