C# 3.0 feature 2--Extension methods

iDotNetSpace發表於2009-08-12
Extension method,可以對現有類功能進行擴充,從而使該型別的例項具有更多的方法(功能)。

有人可能會提出疑問,如果是對類進行擴充,那使用繼承不就ok了?是的,使用繼承確實可以達到擴充功能的目的,但也會帶來更多的問題,比如該使用子類的地方,傳入的卻是父類物件;比如想擴充的類為第三方提供,我們無法得知其內部細節等等。拋開這些統統不談,為了讓一個型別的例項增加一個方法,我們就要使用繼承創造自己的子類?這顯然不是一個好辦法,相對於這些, Extension method給我們提供了一個簡便,靈活的解決方案。

我們先來看一個例子。
C# 3.0 feature 2--Extension methodsnamespace CSharp
C# 3.0 feature 2--Extension methods
{
C# 3.0 feature 2--Extension methods    
class Program
C# 3.0 feature 2--Extension methods    
{
C# 3.0 feature 2--Extension methods        
static void Main(string[] args)
C# 3.0 feature 2--Extension methods        
{
C# 3.0 feature 2--Extension methods            
int i = 6;
C# 3.0 feature 2--Extension methods            Console.WriteLine(i.Square());
C# 3.0 feature 2--Extension methods        }

C# 3.0 feature 2--Extension methods    }

C# 3.0 feature 2--Extension methods    
static class Extensions
C# 3.0 feature 2--Extension methods    
{
C# 3.0 feature 2--Extension methods        
public static int Square(this int i)
C# 3.0 feature 2--Extension methods        
{
C# 3.0 feature 2--Extension methods            
return i * i;
C# 3.0 feature 2--Extension methods        }

C# 3.0 feature 2--Extension methods    }

C# 3.0 feature 2--Extension methods}

上面的例子中,我們對int的方法進行了擴充,為其增加了Square方法。

下面是編繹後的IL程式碼。
C# 3.0 feature 2--Extension methods.method private hidebysig static void  Main(string[] args) cil managed
{
C# 3.0 feature 2--Extension methods  .entrypoint
C# 3.0 feature 2--Extension methods  
// Code size       16 (0x10)
C# 3.0 feature 2--Extension methods
  .maxstack  1
C# 3.0 feature 2--Extension methods  .locals init ([
0] int32 i)
C# 3.0 feature 2--Extension methods  IL_0000:  nop
C# 3.0 feature 2--Extension methods  IL_0001:  ldc.i4.
6
C# 3.0 feature 2--Extension methods  IL_0002:  stloc.
0
C# 3.0 feature 2--Extension methods  IL_0003:  ldloc.
0
C# 3.0 feature 2--Extension methods  IL_0004:  call       int32 CSharp.Extensions::Square(int32)
C# 3.0 feature 2--Extension methods  IL_0009:  call       
void [mscorlib]System.Console::WriteLine(int32)
C# 3.0 feature 2--Extension methods  IL_000e:  nop
C# 3.0 feature 2--Extension methods  IL_000f:  ret
C# 3.0 feature 2--Extension methods}
 // end of method Program::Main

   我們發現原來extension method也沒什麼玄乎的,編繹器會將其編繹為對Square(i)的呼叫,原來就是靜態類中方法呼叫。
   將Extension Method改為靜態方法,並在Main函式中直接呼叫
C# 3.0 feature 2--Extension methodsnamespace CSharp
C# 3.0 feature 2--Extension methods
{
C# 3.0 feature 2--Extension methods    
class Program
C# 3.0 feature 2--Extension methods    
{
C# 3.0 feature 2--Extension methods        
static void Main(string[] args)
C# 3.0 feature 2--Extension methods        
{
C# 3.0 feature 2--Extension methods            
int i = 6;
C# 3.0 feature 2--Extension methods            Console.WriteLine(Extensions.Square(i));
C# 3.0 feature 2--Extension methods        }

C# 3.0 feature 2--Extension methods    }

C# 3.0 feature 2--Extension methods    
static class Extensions
C# 3.0 feature 2--Extension methods    
{
C# 3.0 feature 2--Extension methods        
public static int Square(this int i)
C# 3.0 feature 2--Extension methods        
{
C# 3.0 feature 2--Extension methods            
return i * i;
C# 3.0 feature 2--Extension methods        }

C# 3.0 feature 2--Extension methods    }

C# 3.0 feature 2--Extension methods}
 修改後的IL程式碼
C# 3.0 feature 2--Extension methods.method private hidebysig static void  Main(string[] args) cil managed
C# 3.0 feature 2--Extension methods
{
C# 3.0 feature 2--Extension methods  .entrypoint
C# 3.0 feature 2--Extension methods  
// Code size       16 (0x10)
C# 3.0 feature 2--Extension methods
  .maxstack  1
C# 3.0 feature 2--Extension methods  .locals init ([
0] int32 i)
C# 3.0 feature 2--Extension methods  IL_0000:  nop
C# 3.0 feature 2--Extension methods  IL_0001:  ldc.i4.
6
C# 3.0 feature 2--Extension methods  IL_0002:  stloc.
0
C# 3.0 feature 2--Extension methods  IL_0003:  ldloc.
0
C# 3.0 feature 2--Extension methods  IL_0004:  call       int32 CSharp.Extensions::Square(int32)
C# 3.0 feature 2--Extension methods  IL_0009:  call       
void [mscorlib]System.Console::WriteLine(int32)
C# 3.0 feature 2--Extension methods  IL_000e:  nop
C# 3.0 feature 2--Extension methods  IL_000f:  ret
C# 3.0 feature 2--Extension methods}
 // end of method Program::Main
C# 3.0 feature 2--Extension methods

可以看到,兩種程式碼產生的IL程式碼一模一樣。

下面說下如何定義Extension Method,首先,Extension Method必須定義在普通的 static class內,這裡講的普通是static class不能為泛型(non-generic)或者內嵌(non-nested)的。其次,Extension Method的第一個引數必須為this + 型別 +  變數名。該引數指定了擁有該方法的型別為 this指定的型別。可能有的人會問,即然this指定的型別擁有,那麼可不可以使用型別的私有或受保護的成員?很遺憾,不能。記住,Extension Method僅僅是看起來像是一個型別的方法,但其實質上不是,它更像是靜態型別的靜態方法,事實上,它確實擁有靜態方法所具有的所有功能。

說完了這些,再說一下Extension Method的作用域,它是整個namespace可見的,並且可以通過using namespace來匯入其它名稱空間中的Extension Method.  匯入的擴導方法有沒有可能因為跟原型別的重名方法衝突而導致編繹失敗呢?不會。如果有同名的方法,Extension Method會出現在該方法Intellisense中的Parameter Help和Quick Info中,我們可以象呼叫過載函式一樣呼叫它。
最後再說一下Extension Method的結合順序,它是自左向右結合的,比如x有兩個Extension Method方法A,B,x.A().B()將被編繹為B(A(x)).

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-612015/,如需轉載,請註明出處,否則將追究法律責任。

相關文章