擴展方法使您能夠向現有類型“添加”方法,而無需創建新的派生類型、重新編譯或以其他方式修改原始類型。
MSDN
Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.
傳統的模式下如果想爲一個類型(class)添加一個額外的自定義的特殊的邏輯上,或者業務上的新方法時,你必須重新定義的一個類型來繼承原有的的方法,用繼承類或者接口,但是有些用sealed修飾的,這時候就無法被繼承,例如String,值類型,sealed修飾的類。
擴展方法是C#3.0這個版本提出來的。解決了必須由繼承才能擴展的某個類的弊端,最重要的一點就是很好用。
注意:
擴展方法必須在非嵌套、非泛型的靜態類中定義。
Note that it is defined inside a non-nested<非嵌套>, non-generic<非泛型的> static<靜態> class:
擴展方法的規則有以下幾點:
- 擴展方法必須是擴展方法必須是非嵌套、非泛型的靜態類中定義的;
- 擴展方法的第一個參數要用this關鍵字修飾;
- 第一個方法參數不能有ref 或則out關鍵字修飾的參數;
- 引用項目的命名空間;
- 參數調用兩種;
- 和傳統的調用方法一樣使用<ExtendClass>.<ExtendClassMethod>(參數,參數+?)
- <參數類型>.<ExtendClassMethod>(參數+?)
1 // Define an interface named IMyInterface. 2 namespace DefineIMyInterface 3 { 4 using System; 5 6 publicinterface IMyInterface 7 { 8 // Any class that implements IMyInterface must define a method 9 // that matches the following signature. 10 void MethodB(); 11 } 12 } 13 14 15 // Define extension methods for IMyInterface. 16 namespace Extensions 17 { 18 using System; 19 using DefineIMyInterface; 20 21 // The following extension methods can be accessed by instances of any 22 // class that implements IMyInterface. 23 publicstaticclass Extension 24 { 25 publicstaticvoid MethodA(this IMyInterface myInterface, int i) 26 { 27 Console.WriteLine 28 ("Extension.MethodA(this IMyInterface myInterface, int i)"); 29 } 30 31 publicstaticvoid MethodA(this IMyInterface myInterface, string s) 32 { 33 Console.WriteLine 34 ("Extension.MethodA(this IMyInterface myInterface, string s)"); 35 } 36 37 // This method is never called in ExtensionMethodsDemo1, because each 38 // of the three classes A, B, and C implements a method named MethodB 39 // that has a matching signature. 40 publicstaticvoid MethodB(this IMyInterface myInterface) 41 { 42 Console.WriteLine 43 ("Extension.MethodB(this IMyInterface myInterface)"); 44 } 45 } 46 } 47 48 49 // Define three classes that implement IMyInterface, and then use them to test 50 // the extension methods. 51 namespace ExtensionMethodsDemo1 52 { 53 using System; 54 using Extensions; 55 using DefineIMyInterface; 56 57 class A : IMyInterface 58 { 59 publicvoid MethodB() { Console.WriteLine("A.MethodB()"); } 60 } 61 62 class B : IMyInterface 63 { 64 publicvoid MethodB() { Console.WriteLine("B.MethodB()"); } 65 publicvoid MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); } 66 } 67 68 class C : IMyInterface 69 { 70 publicvoid MethodB() { Console.WriteLine("C.MethodB()"); } 71 publicvoid MethodA(object obj) 72 { 73 Console.WriteLine("C.MethodA(object obj)"); 74 } 75 } 76 77 class ExtMethodDemo 78 { 79 staticvoid Main(string[] args) 80 { 81 // Declare an instance of class A, class B, and class C. 82 A a = new A(); 83 B b = new B(); 84 C c = new C(); 85 86 // For a, b, and c, call the following methods:// -- MethodA with an int argument// -- MethodA with a string argument// -- MethodB with no argument.// A contains no MethodA, so each call to MethodA resolves to // the extension method that has a matching signature. 87 a.MethodA(1); // Extension.MethodA(object, int) 88 a.MethodA("hello"); // Extension.MethodA(object, string)// A has a method that matches the signature of the following call// to MethodB. 89 a.MethodB(); // A.MethodB()// B has methods that match the signatures of the following// method calls. 90 b.MethodA(1); // B.MethodA(int) 91 b.MethodB(); // B.MethodB()// B has no matching method for the following call, but // class Extension does. 92 b.MethodA("hello"); // Extension.MethodA(object, string)// C contains an instance method that matches each of the following// method calls. 93 c.MethodA(1); // C.MethodA(object) 94 c.MethodA("hello"); // C.MethodA(object) 95 c.MethodB(); // C.MethodB() 96 } 97 } 98 } 99 /* Output: 100 Extension.MethodA(this IMyInterface myInterface, int i) 101 Extension.MethodA(this IMyInterface myInterface, string s) 102 A.MethodB() 103 B.MethodA(int i) 104 B.MethodB() 105 Extension.MethodA(this IMyInterface myInterface, string s) 106 C.MethodA(object obj) 107 C.MethodA(object obj) 108 C.MethodB() 109 */
總結的結果
方法的調用次序 類型的實例方法--->當前命名空間下的擴展方法--->導入的其他命名空間擴展方法。
引發疑問
在空引用上調用實例方法或靜態方法時會拋出NullReferenceException異常?那麼在類調用擴展方法時會出現異常嗎?(不使用類中的一些屬性或方法,強調調用)
擴展方法 | 靜態方法 |
TestExtend sExtend=null;
sExtend.NullUse();
|
TestExtend sExtend=null;
NullUse.(sExtend);
|
可能引發的子類污染的問題例如
你本來只想擴展TestExtend 這個類的方法,由於你要使用iSNull這個類型的擴展結果傳入參數(object),結果導致所有的object 類型都擴展了這個方法,這會帶來可怕的後果。
所以在擴展一個類型的方法時,要從確定類型擴展。儘量避免從父類去擴展。
有什麼不對的或者錯誤的地方希望大家給予指正,謝謝
我的開發環境VS2015
DEMO的下載 【http://pan.baidu.com/s/1bY51P8】