c#3.0中一個激動人心的特性就是擴展方法:你可以使用實例方法的語法來調用靜態方法。本文仔細闡述了這一新特性并且給出了幾個相應的例子。
  聲明擴展方法
  擴展方法的行為和靜態方法是非常類似的,你只能在靜態類中聲明它們。為聲明一個擴展方法,你需要給該方法的第一個參數指定this關鍵字,如下例:
// program.cs
public static class emclass
{
 public static int toint32ext(this string s)
 {
  return int32.parse(s);
 } 
 public static int toint32static(string s)
 {
  return int32.parse(s);
 }
}
class program
{
 static void main(string[] args)
 {
  string s = "9";
  int i = s.toint32ext(); // line a
  console.writeline(i);
  int j = emclass.toint32static(s); // line b
  console.writeline(j);
  console.readline();
 }
}
  為編譯如上代碼,你需要安裝visual studio 2005和linq的預覽版。如果你已經安裝了vs2005,那么你將在visual c#的linq preview里看到三個新的工程模板:linq命令行應用程序,linq窗口程序和linq庫。如下操作編譯代碼:
  1. 打開vs2005編輯器,創建一個新工程,在新建工程窗口中選擇linq console作為工程模板。
  2. 將工程命名為extensionmethods,點擊ok。
  3. 將如上代碼鍵入編輯器。
  4. 按下f5編譯工程并運行。
  如果你只是安裝了.net 2.0,那么你可以運行命令行編譯器:
csc.exe /reference:"c:/program files/linq preview/bin
/system.data.dlinq.dll"
/reference:c:/windows/microsoft.net/framework/v2.0.50727/system.dll
/reference:"c:/program files/linq preview/bin/system.query.dll"
/reference:"c:/program files/linq preview/bin/system.xml.xlinq.dll"
/target:exe program.cs
  就像你在如上代碼里所看到的那樣,擴展方法(toint32ext)和普通的靜態方法(toint32static)的不同在于:
  1. 擴展方法的第一個參數有一個this關鍵字,而靜態方法不會在它的參數聲明里有this關鍵字。
  2. 當使用擴展方法的是哦戶,使用this關鍵字聲明的的參數沒有進行傳遞。在上面的例子里,line a就是一個使用擴展方法toint32ext的例子。不需要將參數傳遞給它。當靜態方法在使用的時候,是不能忽略掉任何的參數的。所有的參數必須傳遞進入函數。line b就是一個例子。
  3. 擴展方法只能在靜態類中定義。對于靜態方法,這并不成為一個要求,因為靜態方法可以在一個靜態類或普通類中存在。 
  4. 擴展方法只能針對實例調用。
  擴展方法,盡管本質上還是靜態的,但是只能針對實例調用。如果在一個類中調用它們將會引發編譯錯誤。調用它們的類實例是由聲明中的第一個參數決定的,就是有關鍵字this修飾的那個。
  在il內部
  如果你觀看il里對以上代碼的分析結果,你將會看到如下圖的結果:
  以下是il對于擴展方法toint32ext的分析:
.method public hidebysig static int32 toint32ext(string s) cil managed
{
 .custom instance void [system.query]system.runtime
 .compilerservices.extensionattribute::.ctor() = ( 01 00 00 00 )
 // code size 12 (0xc)
 .maxstack 1
 .locals init ([0] int32 cscode_replacement 200)
 il_0000: nop
 il_0001: ldarg.0
 il_0002: call int32 [mscorlib]system.int32::parse(string)
 il_0007: stloc.0
 il_0008: br.s il_000a
 il_000a: ldloc.0
 il_000b: ret
} // end of method emclass::toint32ext
  以下代碼是il對靜態方法toint32static的分析:
.method public hidebysig static int32 toint32static(string s) cil managed
{
 // code size 12 (0xc)
 .maxstack 1
 .locals init ([0] int32 cscode_replacement 300)
 il_0000: nop
 il_0001: ldarg.0
 il_0002: call int32 [mscorlib]system.int32::parse(string)
 il_0007: stloc.0
 il_0008: br.s il_000a
 il_000a: ldloc.0
 il_000b: ret
} // end of method emclass::toint32static
  .custom instance void: 本行代碼說明本方法只能針對實例使用。
  [system.query]system.runtime.compilerservices.extensionattribute::.ctor() = ( 01 00 00 00 ):本行代碼說明擴展特性被使用了。
  擴展方法轉換
  下表顯示了在編譯時進行的方法轉換
|   | 方法 | 代碼編譯為 | 
| 1  | expr . identifier ( ) | identifier (expr) | 
| 2  | expr . identifier ( args ) | identifier (expr, args) | 
| 3  | expr . identifier <typeargs> ( ) | identifier <typeargs> (expr) | 
| 4  | expr . identifier <typeargs> ( args ) | identifier <typeargs> (expr, args) | 
  如果你在ildasm中檢查main方法的代碼,它將會如下顯示:
.method private hidebysig static void main(string[] args) cil managed
{
 .entrypoint
 // code size 42 (0x2a)
 .maxstack 1
 .locals init ([0] string s,
 [1] int32 i,
 [2] int32 j)
 il_0000: nop
 il_0001: ldstr "9"
 il_0006: stloc.0
 il_0007: ldloc.0
 il_0008: call int32 extensionmethods.emclass::toint32ext(string)
 il_000d: stloc.1
 il_000e: ldloc.1
 il_000f: call void [mscorlib]system.console::writeline(int32)
 il_0014: nop
 il_0015: ldloc.0
 il_0016: call int32 extensionmethods.emclass::
 toint32static(string)
 il_001b: stloc.2
 il_001c: ldloc.2
 il_001d: call void [mscorlib]system.console::writeline(int32)
 il_0022: nop
 il_0023: call string [mscorlib]system.console::readline()
 il_0028: pop
 il_0029: ret
} // end of method program::main
il_0008: call int32 extensionmethods.emclass::
toint32ext(string)
  這里表明方法轉換(expr . identifier ( ) <--> identifier (expr) )發生.
  所以當你調用 int i = s.toint32ext();, 編譯器內部進行操作int i = emclass.toint32ext(s);那么,重寫的新生會當作一個靜態方法調用來處理
  標識符按照如下的順序解析:
  1. 最近的包含的命名空間聲明
  2. 每個后繼包含的命名空間聲明
  3. 包含的編譯單元
  下面是方法的從高到低的優先級:
  1. 實例方法
  2. 在同一個命名空間里的擴展方法
  3. 在當前命名空間之外的擴展方法
  為什么使用擴展方法?
  你也許會問:"為什么有了普通的靜態和實例類還需要使用擴展方法呢?"其實,簡單來說就是為了方便。我來舉個例子吧。如果你在過去的一段時間內開發了很多函數形成了一個庫。那么當某人要用這個函數庫的時候,他必須要知道定義了所需的靜態方法的類名。就像下面這個一樣:
a = mylibraryclass.
  這里,intellisense將會彈出并且告訴你可用函數的名字,你只需要挑選你所需要的。然后鍵入你需要的方法名和相關參數。
a = mylibraryclass.desiredfunction(strname)
  使用這種方法,你必須事先知道哪個庫包含了你所要的哪個函數和它的名稱,使用擴展方法就不一樣了:
a = strname.
  這里,intellisense將會彈出,并且顯示可以使用哪些擴展方法。你只需要鍵入你需要的擴展方法:
a = strname.desiredfunction()
  這里無須給出所需的參數名來指定數據類型。  
在對象實例中調用靜態方法  擴展方法提供了一個新的機制用來在對象實例上調用靜態方法。但和實例方法比較起來,它還是在功能上有諸多限制,因此你應該保守的使用它,主要將它哦能夠在實例方法能力所不及的地方。
  c# 3.0并不是一個正式的版本,所以它的標準也沒有最后定稿。因此,這樣的格式也很有可能變化。
收集最實用的網頁特效代碼!