從DEMO開始
先看一個擴充方法的例子:
1 class Program 2 { 3 public static void Main() 4 { 5 Int32 myNum = 1; 6 myNum = myNum.AddToOldNum(1); 7 Console.WriteLine(myNum); 8 } 9 } 10 11 public static class ExpandInt 12 { 13 //擴充方法必須為靜態方法 14 public static int AddToOldNum(this int oldNum,int newNum) 15 { 16 return oldNum + newNum; 17 } 18 }
為一個類型擴充一個方法如此只簡單,但是它究竟為我們做了什麼呢,為什麼我可以調用的AddToOldNum方法?還是讓我們從IL代碼層面來看看吧。
擴充方法剖析
這裡是上面代碼編譯的IL:
1 .method public hidebysig static int32 AddToOldNum( 2 int32 oldNum, int32 newNum) cil managed 3 { 4 .custom instance void [System.Core] 5 System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) 6 // 代碼大小 9 (0x9) 7 .maxstack 2 8 .locals init ([0] int32 CS$1$0000) 9 IL_0000: nop 10 IL_0001: ldarg.0 11 IL_0002: ldarg.1 12 IL_0003: add 13 IL_0004: stloc.0 14 IL_0005: br.s IL_0007 15 IL_0007: ldloc.0 16 IL_0008: ret 17 } // end of method ExpandInt::AddToOldNum
發現它和一般的靜態方法沒什麼區別,唯一不同的是多了一行調用[System.Runtime.CompilerServices.ExtensionAttribute]:
custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
MSDN告訴我System.Runtime.CompilerServices.ExtensionAttribute表明一個法是一種可拓方法, 或一個類或集合包含擴充方法【這裡我也不太懂,嘿嘿】。從這個類型的結尾Extension_Attribute_就可看出它是一個屬性類別。 為我們的AddToOldNum方法添加了必要的中繼資料。
再來看看Main方法裡發生了什麼情況:
1 .method public hidebysig static void Main() cil managed 2 { 3 .entrypoint 4 // 代碼大小 19 (0x13) 5 .maxstack 2 6 .locals init ([0] int32 myNum) 7 IL_0000: nop 8 IL_0001: ldc.i4.1 9 IL_0002: stloc.0 10 IL_0003: ldloc.0 11 IL_0004: ldc.i4.1 12 IL_0005: call int32 ConsoleApplication1.ExpandInt::AddToOldNum(13 int32, int32) 14 IL_000a: stloc.0 15 IL_000b: ldloc.0 16 IL_000c: call void [mscorlib]System.Console::WriteLine(int32) 17 IL_0011: nop 18 IL_0012: ret 19 } // end of method Program::Main
注意這一行,編譯器把我們寫的myNum = myNum.AddToOldNum(1)編譯成這樣:
IL_0005: call int32 ConsoleApplication1.ExpandInt::AddToOldNum(int32,int32)
"執行個體方法"的調用換成了ExpandInt::AddToOldNum(int32,int32)靜態方法的調用,這就是擴充方法的本質所在了。總結
我們真的擴充了Int32類的執行個體方法了嗎?沒有,編譯器幫我們披了一層外衣, 把對“執行個體方法”的調用在編譯時間期改變成了靜態類中的靜態方法的調用,所以擴充方法是一種編譯時間技術。當擴充方法和執行個體方法簽名相同時,執行個體方法優先使用。