我想了解CLR如何實現引用類型和多態性。我已經提到了Don Box的Essential .Net Vol 1,這對於驗證大部分內容非常有幫助。但是當我嘗試使用一些IL代碼來更好地理解時,我被以下問題卡住/困惑。callvirt如何在引擎蓋下工作?
我會盡我所能解釋問題。 考慮下面的代碼
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
我期待這個代碼NOT運行作爲對象引用指向基礎的目的,並且沒有方法基礎對象的方法表將具有Derived類中定義的方法m()的條目。
但神奇的是,這段代碼執行Derived.m()!
因此,有兩個問題我不明白,在上面的代碼:
是什麼類型的意義在下面的IL代碼指定?我試圖通過將其更改爲不同的類型(例如System.Exception !!)來進行試驗,並且不報告錯誤。爲什麼??
.locals的init([0]類Console1.Base d)
- 究竟如何callvirt的作品?呼叫如何被路由到Derived.m()?
在此先感謝!
問候, 阿賈伊
@ulrichb:我不認爲他能做到這一點。它會像`Base b = new Base();((Derived)b).m`類似,除非他真的沒有使用cast(這會引發異常)。 – CodesInChaos 2010-11-27 16:19:51
代碼是否可驗證? – CodesInChaos 2010-11-27 16:20:55
@CodeInChaos:沒有代碼是不可驗證的! PEVerify給出「意外的堆棧類型」錯誤。 – ajay 2010-11-28 03:15:10