3.2 擴展方法(Extension Methods)
Lambda表達式是查詢體系(query architecture)的一個重要部分,擴展方法(Extension methods)是另一個重要組成部分。擴展方法結合了“duck typing”(一種可替代任何類型的類型)的彈性(flexibility)特點,使得動態語言(dynamic languages,如JavaScript)更加流行(popular),同時又有靜態型語言(statically typed languages,如C++和Java)的優秀性能(performance)和編譯時驗證(compile-time validation)的特點。通過擴展方法,第三方(third parties)可以增加使用了新方法的類型(type with new methods)的公共合同(public contract),使得獨立型的開發者(individual type authors)還能提供他們對這些方法的自己專門的實現(specialized implementation)。
擴展方法定義在靜態類(static classes)里,就像靜態方法(static methods)一樣,但是它們在CLR元數據(CLR metadata)里卻被標記為[System.Runtime.CompilerServices.Extension]。程序語言都被鼓勵(encourage)為擴展方法提供一種直觀的語法(direct syntax)。在 C# 語言里,擴展方法是由 this 指針(this modifer)標示(indicate)的,它必須應用于(applied to)擴展方法的第一個參數。下面讓我們來看看一段最簡單的查詢操作符(query operator)的定義代碼:






















擴展方法的第一個參數的類型標示(indicate)擴展的內容所應用(the extension applies to)的類型。在上面的例子中,擴展方法 Where 擴展自 IEnumerable<T> 類型。因為 Where 是一個靜態方法(static method),所以我們可以像其他靜態方法一樣直接調用它(invoke it directly):



然而,擴展方法的一個獨特(unique)的特點是我們還可以使用實例的語法(using instance syntax)來調用它:

擴展方法是基于擴展方法的活動范圍內(in scope)在編譯時(compile-time)決定的(resolved)。當引入(import)一個命名空間(namespace)時(在 C# 里使用 using 語句,在VB 里使用 Import 語句),所有的擴展方法是由從 namespace 帶入活動范圍(brought into scope)的靜態類(static classes)定義的。
標準查詢操作符(standard query operators)在 System.Query.Sequence 類型里定義成擴展方法。當檢查標準查詢操作符時,你將注意到它們中所有的方法根據(in terms of)接口IEnumerable<T> 來定義的(除了 OfType,將在后面介紹它)。這意味著每一個兼容 IEnumerable<T> 接口的信息源(information source)在 C# 語言里通過簡單地添加如下的 using 語句就可以獲取標準查詢操作符:

用戶如果想用一個指定的類型(specific type)來替換標準查詢操作符,可以在有一致標識(compatible signatures)的指定的類型上定義他們自己的相同名字的方法(same-named methods),另一種方法是通過擴展指定的類型來(extend the specific type)定義相同名字的方法。用戶如果想完全避免(eschew)使用標準查詢操作符,可以簡單地將 System.Query 置于活動范圍之外,并且為 IEnumerable<T> 接口寫出他們自己的擴展方法就可以了。
按照分析規則,擴展方法被賦予了最低優先權(lowest priority),它們只是在沒有相適配(suitable)的目標類型(target type)和它們的基類型(base types)時才被使用。這個規則允許用戶自定的類型(user-defined types)提供他們自己的查詢操作符,比標準查詢操作符更優先使用(take precedence over)。例如,考慮用戶自定義 collection 的實現如下:

























通過給出這個類的定義,下面的程序:




將使用 MySequence.Where 的實現,而不是擴展方法,因為類實體方法(instance methods)比擴展方法(extension methods)更優先使用。
前面的提及(mentioned earlier)了屬于標準操作符(standard operator)一員但不是擴展自基于IEnumerable<T> 接口(IEnumerable<T>-based)的信息源的 OfType 類型,下面讓我們來看看 OfTyoe 查詢操作符:








OfType 即接受基于IEnumerable<T> 接口的信息源,也接受那些在 .NET Framework 1.0 中出現的非參數化的 IEnumerable 接口(non-parameterized IEnumerable interface)。OfType 操作符允許用戶在標準的 .NET collections 類(classic .NET collections)上應用標準查詢操作符,就像下面的程序:






在這個例子中,變量 modern 產生了與變量 classic 一樣的順序的數據列表(same sequence of values),但是不同的是它的類型兼容最新的 IEnumerable<T> 代碼(modern IEnumerable<T> code),包括標準查詢操作符。
OfType 操作符對新的信息源也是有用的,因為它允許從基于類型的信息源(source based on type)中過濾出數據(filtering values from)。當要制作新的順序的時候(producing the new sequence),OfType 簡單的忽略(omits)原有序列的成員(members of the original sequence)就可以了,這是與類型實參(type argument)不相符的。分析下面的程序,目標是將 string 字符串數據從一個有不同種類數據的數組(heterogeneous array)中分解出來:





當在 foreach 語句中列舉(enumerate)變量 justStrings 中的數據時,將得到兩個依次為“Hello”和“World”的 string 字符串序列(a sequence of two strings )。
待續, 錯誤難免,請批評指正,譯者Naven