我可不可以這樣理解,性能只是在編譯時有損失,編譯之後就和普通的靜態方法調用一樣了,沒有任何區別,之所以能得出這個結論是因為通過比較如下的兩種調用方式和對應的IL代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Extention { class Program { static void Main(string[] args) { var dt = DateTime.Now; var dtString = dt.DT(); var dtString1 = Extention.Extention1.DT(dt); var dtString2 = Extention.Extention1.DT1(dt); Console.ReadLine(); } } public static class Extention1 { public static string DT(this DateTime dt) { return dt.ToString(); } public static string DT1(DateTime dt) { return dt.ToString(); } } }
Main函數中對DT的三種調用生成的IL代碼如下:
C#編譯器是如何快速的定位擴展方法的匹配的呢?
在C#中,一旦用this關鍵詞標記了某個靜態方法的第一個參數,編譯器就會在內部向該方法應用一個定制特性ExtensionAttribute;
另外,任何靜態類只要包含至少一個擴展方法,它的元數據也會應用這個特性,類似的,程序集中只要包含了至少一個符合上述特點的靜態類,它的元數據中也會應用這個特性,
這樣一來,如果代碼調用了一個不存在的實例方法,編譯器就能快速的掃描引用的所有程序集,判斷他們哪些包含了擴展方法,然後在這些程序集中,可以只掃描包含了擴展方法的靜態類,
在每個這樣的靜態類中,可以只掃描擴展方法來查找匹配,利用這些技術,代碼能以最快的速度編譯完畢;
.class public auto ansi abstract sealed beforefieldinit Extention.Extention1 extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Methods .method public hidebysig static string DT ( valuetype [mscorlib]System.DateTime dt ) cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) // Method begins at RVA 0x2088 // Code size 19 (0x13) .maxstack 1 .locals init ( [0] string CS$1$0000 ) IL_0000: nop IL_0001: ldarga.s dt IL_0003: constrained. [mscorlib]System.DateTime IL_0009: callvirt instance string [mscorlib]System.Object::ToString() IL_000e: stloc.0 IL_000f: br.s IL_0011 IL_0011: ldloc.0 IL_0012: ret } // end of method Extention1::DT .method public hidebysig static string DT1 ( valuetype [mscorlib]System.DateTime dt ) cil managed { // Method begins at RVA 0x20a8 // Code size 19 (0x13) .maxstack 1 .locals init ( [0] string CS$1$0000 ) IL_0000: nop IL_0001: ldarga.s dt IL_0003: constrained. [mscorlib]System.DateTime IL_0009: callvirt instance string [mscorlib]System.Object::ToString() IL_000e: stloc.0 IL_000f: br.s IL_0011 IL_0011: ldloc.0 IL_0012: ret } // end of method Extention1::DT1 } // end of class Extention.Extention1