2008-12-11 112 views
20

當使用C#的「作爲」關鍵字,使這些失敗鑄造,空獲取返回。背景中發生了什麼?它是否僅僅是壓制一個異常,所以我不必爲失敗編寫處理代碼?C#鑄造性能影響

我很感興趣,相比於包裹在一個try-catch典型的投它的性能特點。

回答

49

它使用IL指令isinst來執行轉換,而不是鑄造時所使用的castclass指令。這是一個特殊的指令,如果它有效就執行強制轉換,否則在堆棧上如果不是則將其保留在堆棧上。所以不,它不僅僅是壓制一個異常,並且比這個快幾個數量級。

注意,有在行爲isinst指令和castclass之間的一些差異 - 其中最主要的是isinst不考慮用戶定義類型轉換操作符,只考慮直接的繼承層次,例如如果你沒有繼承層次,但有明確的轉換操作符定義了以下兩類:

class A 
{ 
    public int Foo; 
} 

class B 
{ 
    public int Foo; 

    public static explicit operator B(A a) 
    { 
     return new B { Foo = a.Foo }; 
    } 
} 

那麼下面會成功:

var a = new A { Foo = 3 }; 
var b = (B)a; 
Console.WriteLine(b.Foo); // prints 3 

但是下面無法編譯,並顯示錯誤「無法轉換類型「A」通過引用轉換「B」,裝箱轉換,取消裝箱轉換,包裝轉換或null類型轉換」

var a = new A { Foo = 3 }; 
var b = a as B; 

所以,如果你有一個y用戶定義的強制轉換(對於這個原因和其他原因,這對於引用類型來說通常是一個壞主意),那麼你應該意識到這種差異。

+0

它不能編譯的原因是什麼?我認爲'as'僅在代碼執行時評估?這是否意味着編譯器也會在編譯期間檢查強制轉換? – faulty 2008-12-12 11:12:39

7

,並增加Greg的優秀帖子...

第一次在運行一個新的類型被引用時,CLR加載到內存中一個名爲COREINFO_CLASS_STRUCT(或類似的東西),它包含,除其他事項外結構,的指針COREINFO_CLASS_STRUCT對象的基類該對象從派生...這有效地創建COREINFO_CLASS_STRUCT對象的繼承鏈的類型,其終止於COREINFO_CLASS_STRUCTSystem.Object的鏈接列表。當您執行isinst,(或者是類似的方法castclass),它只是找到具體類型,你正在檢查的對象COREINFO_CLASS_STRUCT存儲結構,遍歷這個鏈表來看看,如果你想投的類型是在列表。

它還包含一個指向包含由類型,如果你正試圖轉換爲一個接口,它必須單獨搜索實現的所有接口,一個單獨的數組。