一、基礎
擴充方法使您能夠向現有類型“添加”方法,而無需建立新的派生類型、重新編譯或以其他方式修改原始類型。擴充方法是一種特殊的靜态方法,調用擴充方法與調用在類型中實際定義的方法之間沒有明顯的差異。擴充方法是可以通過使用執行個體方法文法調用的靜态方法。效果上,使得附加的方法擴充已存在類型和構造類型成為可能。他可以對現有類功能進行擴充,進而使該類型的執行個體具有更多的方法。擴充方法有助于把今天動态語言中流行的對快速錄入支援的靈活性,與強類型語言之性能和編譯時驗證融合起來。這裡先舉一個msdn中的例子:
下面的示例示範為 System.String 類定義的一個擴充方法。假設我要分析一個字元串,希望得到字元串中單詞的個數,一般情況下我們可能使用一個統計的函數來解決這個問題
代碼
但這樣用起來感覺上可能會很别扭,這個WordCount方法如果就是字元串類中的一個方法多好,像所有字元串的執行個體方法一樣用。這裡我們引出擴充方法來解決這個問題。
注意,上面的靜态方法在第一個類型是string的參數變量前有個“this”關鍵詞,這告訴編譯器,這個特定的擴充方法應該添加到類型為“string”的對象中去。
使用 using 指令将 WordCount 擴充方法放入範圍中:
using ExtensionMethods;
string s = "Hello Extension Methods";
int i = s.WordCount();
二、應用場景
1、擴充類庫中已經存在的類
比方說我們是無法改變系統已經存在的類的,就像上例中我們無法在string類中添加WordCount方法,但我又希望在使用時直接使用
2、多個類實作接口時有些方法實作方式相同,是以不希望每個實作類中重新實作一遍
假如系統中使用者接口需要兩個類實作,希望IUser接口聲明的實體都有檢測Email的方法IsUniqueEmail,而實際上這個方法在所有實作類中的實作邏輯都是一樣的,而我們如果把這個方法添加到IUser中,那麼兩個類就要都實作一遍IsUniqueEmail的邏輯。中間加一層繼承關系也可以解決問題,這種方式會增加維護成本,這時我們可以使用擴充方法
如下圖:
代碼模拟如下:
static void Main(string[] args)
{
IUser user = new UserLinqToOracle();
Console.WriteLine(user.IsUniqueEmail(""));
}
三、擴充方法要點
1、擴充方法的本質為将執行個體方法調用在編譯期改變為靜态類中的靜态方法調用。事實上,它确實擁有靜态方法所具有的所有功能。
2、通常,您更多時候是調用擴充方法而不是實作您自己的擴充方法。由于擴充方法是使用執行個體方法文法調用的,是以不需要任何特殊知識即可從用戶端代碼中使用它們。若要為特定類型啟用擴充方法,隻需為在其中定義這些方法的命名空間添加 using 指令。
3、擴充方法的優先級:現有執行個體方法優先級最高,其次為最近的namespace下的靜态類的靜态方法,最後為較遠的namespace下的靜态類的靜态方法。(與接口或類方法具有相同名稱和簽名的擴充方法永遠不會被調用 )
結果為“來源于執行個體方法:lfm”
結果為:“來源于較近的擴充方法:lfm”
4、在接口上擴充的方法,如果用接口聲明時會優先使用基于接口的擴充方法
但如果接口中又被添加了相應的方法,将優先使用執行個體方法
5、在代碼中,可以使用執行個體方法文法調用該擴充方法。但是,編譯器生成的中間語言 (IL) 會将代碼轉換為對靜态方法的調用。是以,并未真正違反封裝原則。實際上,擴充方法無法通路它們所擴充的類型中的私有變量。
四、擴充方法通用準則
1、通常,建議您隻在不得已的情況下才實作擴充方法,并謹慎地實作。隻要有可能,必須擴充現有類型的用戶端代碼都應該通過建立從現有類型派生的新類型來達到這一目的。
2、在使用擴充方法來擴充您無法更改其源代碼的類型時,您需要承受該類型實作中的更改會導緻擴充方法失效的風險。
3、如果您确實為給定類型實作了擴充方法,請記住以下兩點:
如果擴充方法與該類型中定義的方法具有相同的簽名,則擴充方法永遠不會被調用。
擴充方法在命名空間級别被放入範圍中。例如,如果您在同一個名為 Extensions 的命名空間中具有多個包含擴充方法的靜态類,則這些擴充方法将全部由 using Extensions; 指令放入範圍中。
本文轉自 你聽海是不是在笑 部落格園部落格,原文連結:http://www.cnblogs.com/nuaalfm/archive/2010/05/24/1742951.html ,如需轉載請自行聯系原作者