[C#][LINQ]Extension Method
Extension Method可以讓新建立的方法被加入至現有型別之中,
不需要另外建立新的衍生型別(Derived Type),也可以對原來型別進行修改,以達到擴充功能目的。
而LINQ大量使用Extension Method,讓有實作IEnumerable介面的集合類別可支援LINQ查詢方法。
Extension Method在使用上有幾點要注意:
一、擴充方法的類別必須宣告為static,而其中成員必須是pulic與static 型態。
二、方法第一個參數加this 修飾詞,來表示所要擴充的目標型別。
[更詳細可參考HOW TO:實作和呼叫自訂擴充方法 (C# 程式設計手冊)]
針對 System.String 類別 (Class) 定義的擴充方法(引用MSDN範例)
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
Enumerable Extension Method分類如下
上述列表的方法可說是LINQ運算式能夠順利運作的關鍵,如果能善用適當擴充方法可說對查詢效能有不小的影響。
就好比我前篇文章中的LINQ查詢運算式,假如我利用Take或FirstOrDefault..等來取得我要的查詢結果,
而不單單只有select from where這麼簡單,那在效能上就不會和傳統foreach方法有太大的差距。
這篇我就來了解一下LINQ To Objects運算式的執行過程。
一個基本的LINQ查詢條件運算式
string[] data = new string[ 5 ] { "TW", "USA", "CA", "JP", "KR" };
IEnumerable<string> items = from c in data
where c == "JP"
select c;
foreach( string item in items )
{
Console.WriteLine( item );
}
我們利用Reflector來看一下Compile後的程式碼
可以看到Compiler幫我們自動建立一個匿名委派instance和<Main>b__0方法,
以及在foreach中我們看到會使用Enumerable.Where來返回篩選過的元素並在畫面印出。
ps.可以看到這裡只使用Where擴充方法,所以會逐一比對集合中的所有元素(因為MoveNext != false),
當然如果這時我們插入一個break(如下圖),那整個執行過程將變成,篩選 c == JP "為真" 時離開Where MoveNext方法,
畫面印出item,並離開foreach迴圈,這時當然也不可能在進入Where MoveNext方法,去篩選過濾下一個元素,
如果後續還有幾千個元素都將省下篩選比對作業過程所耗費的時間。
加入break。
<Main>b__0
Where
判斷source屬於那種集合類型並返回相對應集合元素。
WhereEnumerableIterator(擷取部分)
WhereEnumerableIterator會將所傳遞進來的參數soruce和predicate分別指派給 this.source(資料來源) 和 this.predicate(過濾條件)。
這裡可以看到MoveNext方法如何過濾條件返回我們要的元素。
取得source.GetEnumerator()並指派給 this.enumerator,
while判斷 this.enumerator.MoveNext,
如果等於 true 就繼續判斷過濾條件是否相等,
如果相等則將元素指派給base.current (屬性) ,
而Console.WriteLine( item ),item就是在取得base.current這屬性值。
使用LINQ查詢運算式一定要適當善用擴充方法(select all 列外 ),
因為這可以讓自己寫的LINQ運算式既可處理複雜資料運算,
也同時兼具一定的查詢效能。
參考