首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

LINQ 演進歷程與對 C# 設計的影響(二):Lambda 運算式與擴充方法

     編輯:關於C語言

Lambda 運算式

Lambda 運算式是一種語言功能,在許多方面類似於匿名方法。事實上,若 Lambda 運算式優先引入語言,則不需要匿名方法。基本概念是將代碼視為資料。在 C# 1.0 中,通常可將字串、整數、參考型別等傳遞給方法以便操作那些值。匿名方法與 Lambda 運算式擴充值的範圍以包含代碼區塊。此概念常見於函數式程式設計。

我們再借用以上範例,並用 Lambda 運算式取代匿名方法:

IEnumerable locals = EnumerableExtensions.Where(customers, c => c.ZipCode == 91822);

有幾個注意事項。對初學者而言,Lambda 運算式簡明扼要的原因有很多。首先,未使用 delegate 關鍵字引入建構。取而代之的是新運算子 =>,通知編譯器這不是正則運算式。其次,Customer 型別從使用中推斷。此例中 Where 方法簽名如下:

public static IEnumerable Where(IEnumerable items, Func<T, bool> predicate)

編譯器能推斷 "c" 指 Customer,因 Where 方法第一個參數為 IEnumerable,故 T 實際上必須是 Customer。利用此知識,編譯器還可驗證 Customer 擁有 ZipCode 成員。最後,未指定 return 關鍵字。語法形式中回傳成員被省略,但這只是為語法便利。運算式結果仍視為回傳值。

與匿名方法同樣,Lambda 運算式也支援變數捕獲。例如,對於在 Lambda 運算式主體內包含 Lambda 運算式的方法,可參考其參數或區域變數:

public IEnumerable LocalCusts(IEnumerable customers, int zipCode)
{
    return EnumerableExtensions.Where(customers, c => c.ZipCode == zipCode);
}

最後,Lambda 運算式支援更冗長語法,允許顯式指定型別與執行多條陳述式。例如:

return EnumerableExtensions.Where(customers, (Customer c) => { int zip = zipCode; return c.ZipCode == zip; });

好消息是,我們向原始文章提議的理想語法邁進一大步,並利用一個通常能在查詢運算子外發揮作用的語言功能實現此目標。讓我們再看一下目前階段:

IEnumerable locals = EnumerableExtensions.Where(customers, c => c.ZipCode == 91822);

這裡存在明顯問題。客戶目前必須知道 EnumerableExtensions 類別,而非思考可在 Customer 上執行的操作。另外,多個運算子情況下,使用者必須逆向思維以撰寫正確語法。例如:

IEnumerable locals = EnumerableExtensions.Select(
    EnumerableExtensions.Where(customers, c => c.ZipCode == 91822), c => c.Name);

請注意,Select 屬於外部方法,儘管它在 Where 方法結果基礎上執行。理想語法應更類似:

sequence locals = customers.where(ZipCode == 98112).select(Name);

因此,是否可利用另一語言功能進一步接近理想語法?

擴充方法

結果證明,更好語法將以稱為擴充方法的語言功能形式出現。擴充方法基本上屬於可透過實例語法呼叫的靜態方法。上述查詢問題根源在於我們嘗試向 IEnumerable 新增方法。但若要新增 Where、Select 等運算子,則所有現有與未來實作類別都必須實作那些方法。儘管那些實作絕大多數相同。在 C# 中共用「介面實作」的唯一方法是使用靜態方法,這是我們先前使用 EnumerableExtensions 類別的一個成功方法。

假設我們轉而將 Where 方法寫為擴充方法。那麼查詢可重寫為:

IEnumerable locals = customers.Where(c => c.ZipCode == 91822);

對於此簡單查詢,該語法近乎完美。但將 Where 方法寫為擴充方法的真正含義是什麼?其實非常簡單。基本上,因靜態方法簽名發生變更,故在第一個參數新增 "this" 修飾詞:

public static IEnumerable Where(this IEnumerable items, Func<T, bool> predicate)

此外,必須在靜態類別中宣告該方法。靜態類別是一種只能包含靜態成員、在類別宣告中用 static 修飾詞表示的類別。這就是它的全部含義。此宣告指示編譯器允許在任何實作 IEnumerable 的型別上用與實例方法相同語法呼叫 Where。但是,必須能從當前作用域存取 Where 方法。當包含類型處於作用域內時,方法也在作用域內。因此,可透過 using 指示詞將擴充方法引入作用域。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved