[C#][LINQ]Extension Method

  • 7000
  • 0
  • C#
  • 2010-09-11

[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分類如下

image

上述列表的方法可說是LINQ運算式能夠順利運作的關鍵,如果能善用適當擴充方法可說對查詢效能有不小的影響。

就好比我前篇文章中的LINQ查詢運算式,假如我利用TakeFirstOrDefault..等來取得我要的查詢結果,

而不單單只有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後的程式碼

image

可以看到Compiler幫我們自動建立一個匿名委派instance和<Main>b__0方法,

以及在foreach中我們看到會使用Enumerable.Where來返回篩選過的元素並在畫面印出。

 

ps.可以看到這裡只使用Where擴充方法,所以會逐一比對集合中的所有元素(因為MoveNext != false),

當然如果這時我們插入一個break(如下圖),那整個執行過程將變成,篩選 c == JP "為真" 時離開Where MoveNext方法,

畫面印出item,並離開foreach迴圈,這時當然也不可能在進入Where MoveNext方法,去篩選過濾下一個元素,

如果後續還有幾千個元素都將省下篩選比對作業過程所耗費的時間。

image

加入break。

 

<Main>b__0

image

 

Where

image

判斷source屬於那種集合類型並返回相對應集合元素。

 

WhereEnumerableIterator(擷取部分)

image

image

WhereEnumerableIterator會將所傳遞進來的參數soruce和predicate分別指派給 this.source(資料來源) 和 this.predicate(過濾條件)。

 

image

這裡可以看到MoveNext方法如何過濾條件返回我們要的元素。

取得source.GetEnumerator()並指派給 this.enumerator,

while判斷 this.enumerator.MoveNext,

如果等於 true 就繼續判斷過濾條件是否相等,

如果相等則將元素指派給base.current (屬性) ,

而Console.WriteLine( item ),item就是在取得base.current這屬性值。

 

使用LINQ查詢運算式一定要適當善用擴充方法(select all 列外 ),

因為這可以讓自己寫的LINQ運算式既可處理複雜資料運算,

也同時兼具一定的查詢效能。

 

 

參考

擴充方法 (C# 程式設計手冊)

HOW TO:實作和呼叫自訂擴充方法 (C# 程式設計手冊)

Standard Query Operators Overview