以前總聽說擴展方法擴展方法,只是聽說是C#3.0后出來的新玩意,也僅僅是知道Linq中用到好多的擴展方法,但是他究竟是個什么東東,怎么用它,用它的好處是什么,總是模模糊糊,那么我們今天就嘗試揭開它神秘的面紗。
我們現在看到每個方法都和聲明它的類關聯,但是C#3.0的擴展方法的特性擴展了這個邊界,允許編寫和聲明它的類之外的類關聯的方法。想要知道如何利用這個特征,我們先看一個例子:
class MyData { double D1,D2,D3; public MyData(double d1,double d2,double d3) { D1=d1;D2=d2;D3=d3; } public double Sum() { return D1+D2+D3; } }
這是一個非常簡單而且功能有限,但假設它含有另外一個方法會更有用,該方法返回三個數據的平均值.那么我們有幾種方法可以實現這個增加的功能.
- 如果我們有源代碼,那么我們可以直接修改這個類,將方法直接添加進去.
- 然而,如果我們不能修改這個類,例如,如果這個類在一個第三方的類庫中,那么只要它不是密封的,那么我們可以把它當作基類并在派生類中實現這個新增的方法.
如果我們不能訪問代碼,或該類是密封的,或有其它設計原因使這些方法不能工作,那么我們不得不在另外一個類中使用該類的公有可用成員編寫一個方法.
例如,我們可以編寫一個下面代碼中這樣的類:
上面代碼包含一個名稱為ExtendMyData的靜態類,它包含一個名稱為Avarage的靜態方法,該方法實現了新增的功能.
調用代碼:
public class MyClass { public static void Main() { MyData md=new MyData(1,2,3); Console.WriteLine("Average:{0}",ExtendMyData.Average(md)); } }
這段代碼輸出: Average:2
盡管這是非常好的解決方案,但如果能在類的實例自身調用該方法,而不是創建一個作用于它的類的實例,它將會更優雅。下面兩行代碼闡明了它們的區別。第一行使用剛展示的方法:在另一個類的實例上調用靜態方法。第二行展示了我們愿意使用的形式:在對象自身上調用實例犯非法。
ExtendMyData.Average(md);//在一個類的實例上調用靜態方法 md.Average(); //在對象自身上調用實例方法
擴展方法允許你使用第二種形式,即使第一種形式可能是編寫這種調用的正確方法。通過對方法Average的聲明做一個小小的改動,就可以實現實例調用方式。需要修改的是在參數生命中的類型名稱前增加關鍵字this,如下面所示。把this關鍵字加到靜態類的靜態方法的第一個參數上,把該方法從ExtendMyData的正規方法改變為類MyData的擴展方法。現在兩種調用方式都可以使用:
static class ExtendMyData { public static double Average(this MyData md) { } }
擴展方法重要的需求如下:
- 聲明擴展方法的類必須聲明為static.
- 擴展方法本身必須聲明為static.
- 擴展方法必須包含關鍵字this作為它的第一個參數類型,并在后面跟著它所擴展類的名稱。
另外需要注意的是:C#只支持擴展方法,不支持擴展屬性、擴展事件等。
下面代碼展示了展示了一個完整的程序,注意方法Average完全如同它是MyData的實例成員那樣被調用!
using System; using System.Collections.Generic; public class MyClass { public static void Main() { MyData md=new MyData(1,2,3); Console.WriteLine("Sum:{0}",md.Sum()); Console.WriteLine("Average:{0}",md.Average()); } } class MyData { double D1,D2,D3; public MyData(double d1,double d2,double d3) { D1=d1;D2=d2;D3=d3; } public double Sum() { return D1+D2+D3; } } static class ExtendMyData { public static double Average(this MyData md) { return md.Sum()/3; } }
為了方便大家理解,我又增加了一個例子。分別為string 和集合做擴展方法:
using System; using System.Collections.Generic; using System.Collections; using Extend;//擴展方法的命名空間 namespace Mytest { public class MyClass { public static void Main() { string str = "{0}先生。".With("幕三少"); Console.WriteLine("您好!:"+str); //調用集合的擴展方法 str.ShowItems<char>(); Console.Read(); } } }
namespace Extend { static class ExtendMyData { public static string With(this string content,params string[] args) { return string.Format(content,args); } //為集合做擴展方法 public static void ShowItems<T>(this IEnumerable<T> items) { foreach (var item in items) { Console.WriteLine(item); } } } }
文章列表