2015-12-16 100 views
5
.method public static void Test<class T>(object A_0) cil managed 
{ 
    // Code size  13 (0xd) 
    .maxstack 1 
    .locals init (!!T V_0) 
    IL_0000: ldarg.0 
    IL_0001: isinst  !!T 
    IL_0006: unbox.any !!T 
    IL_000b: stloc.0 
    IL_000c: ret 
} // end of method DemoType::Test 

平等C#代碼:CIL unbox_any指令 - 奇怪的行爲

public static void Test<T>(object o) where T : class 
{ 
    T t = o as T; 
} 

我的問題是:

  1. 爲什麼unbox.any被稱爲?如果你只是做

    var a = father as child 
    

    isinst按照壓會打電話沒有unbox.any,如果我將刪除一般定義,我會盡力投(isinst)對象的一些類,沒有unbox.any將被調用。

  2. 也許unbox.any被調用是因爲泛型定義,所以在這種情況下unbox.any需要拋出一個NullReferenceException,因爲isinst指令的答案在此鑄造中返回null。見unbox_any。如果你嘗試運行這段代碼,你會發現沒有拋出異常。

更新

我能理解unbox_any監守對象類型參數,它嘗試isinst檢查後,將其轉換爲具體類型。也許泛型影響也。

我的問題是,爲什麼不在unbox.any中拋出異常,如果obj我們試圖unbox到T是空的?

該文檔說:「如果obj是空引用,則拋出NullReferenceException。

+0

你能詳細說說這有什麼奇怪的嗎?對我來說這是有道理的。在第(2)點中,你也沒有問過問題。 – usr

+0

@usr首先,我想驗證爲什麼unbox_any被調用。他們兩個都叫什麼意思? (isinst和unbox_any)第二,更重要的是,爲什麼如果傳遞給unbox_any的obj爲空,則不會引發異常? –

回答

4

unbox是保持驗證者高興。驗證者對於知道類型參數T總是要成爲引用類型並不特別聰明,因此C#編譯器會發出這些不必要的開箱。

如果您搜索了Unbox_any和IsVerifierReference的Roslyn源代碼,您會發現這發生在代碼生成器周圍的很多地方。

抖動會在生成代碼時知道類型參數是否爲引用,並且應該生成體面的代碼,而不管看似不必要的指令如何。

+1

如果有人對它感興趣,我建議看看[這裏](http://stackoverflow.com/questions/34382683/jitter-logic-to-remove-unbox-any?lq=1) –