2010-12-18 44 views
10

我只是想知道擴展方法如何連接到原始類。我知道在IL代碼中它調用了靜態方法,但它是如何做到的以及爲什麼不打破封裝。擴展方法如何掛接

回答

9

擴展方法是通過將this關鍵字在靜態方法中的第一個參數的前面指定的當編譯器看到該屬性時,它知道將擴展方法調用轉換爲適當的靜態方法調用,並將該實例作爲第一個參數傳遞。

由於調用只是普通的靜態方法調用,所以沒有機會破壞封裝;與所有靜態方法一樣,方法只能訪問擴展類型的公共接口。

+0

+1好點:) – 2010-12-18 18:07:42

16

他們不「掛鉤」。

Visaul Studio IDE通過在智能感知列表中顯示它,看起來就像它一樣。

編譯器「知道」如何處理引用,以便使用正確的參數進行正確的方法調用。

這簡直就是syntactic sugar - 這些方法只是靜態方法在單獨的靜態類上。使用this修飾符可讓編譯器「知道」將ExtensionAttribute添加到類中,以將其標記爲擴展方法。

由於擴展方法做其實變化類,只能訪問其公共成員,封裝被保留。

MSDN

擴展方法是一種特殊的靜態方法,但他們被稱爲彷彿他們在擴展類型實例的方法。

(重點煤礦)

4

擴展方法只是語法糖,他們只是靜態方法。您只能訪問其中的公共字段或屬性,就像正常的靜態方法一樣。

public static void SomeExtension(this string s) 
{ 
    ... 
} 

即用於與System.Runtime.CompilerServices.ExtensionAttribute裝飾方法只是語法糖:

[Extension] 
public static void SomeExtension(string s) 
{ 
    ... 
} 

2

關鍵因素是類的實例方法與靜態方法沒有根本的區別。只有一個小細節,他們有一個隱藏的論點。例如,String.IndexOf(char)的方法實際上是這樣的CLR:

public static int IndexOf(string thisRef, char value) { 
    // etc... 
} 

thisRef說法是當你在代碼中使用或訪問成員提供什麼樣的字符串引用的類。如你所見,這是一個從擴展方法到實例方法的小步驟。CLR不需要進行任何更改以支持該功能。

另一個微小的區別是,編譯器發出的代碼檢查這個對於實例方法是否爲空,但對於擴展方法不這樣做。您可以在空對象上調用擴展方法。雖然這可能看起來像一個功能,但它實際上是擴展方法引發的一個限制,實際上並不是該類的成員。

CLR在內部保留了類MethodTable的方法列表。擴展方法不在其中,從而阻止編譯器發出IL指令,它是用於獲取廉價空檢查的'技巧'。明確發出代碼以進行空檢查將是可能的,但他們選擇不這樣做。不太清楚爲什麼。

這樣做的另一個自動結果是擴展方法不能是虛擬的。