C# 2.0 匿名方法語法冗長,Lambda 運算式(=>)提供函數式風格的簡潔語法:
// C# 2.0 匿名方法
delegate(int x) { return x + 1; }
// C# 3.0 Lambda
x => x + 1; // 隱含型別,運算式本體
x => { return x + 1; } // 區塊本體
(int x) => x + 1; // 顯式型別
(x, y) => x * y; // 多參數
() => Console.WriteLine(); // 無參數
x => x + 1| 目標 | 委派類型 | Expression<TDelegate> |
|---|---|---|
| 結果 | 可執行程式碼(IL) | 資料結構(記憶體中樹狀圖) |
| 用途 | 執行邏輯 | 分析、轉譯、遠端執行 |
| 轉換條件 | 相容委派簽名 | 運算式本體 Lambda(無區塊本體) |
Func<int, int> f = x => x + 1; // 委派
Expression<Func<int, int>> e = x => x + 1; // 運算式樹
Lambda L 可轉換為委派 D 需滿足:
ref/out 參數void:L 運算式本體需為合法 statement-expression;區塊本體不可有帶運算式的 returnvoid:L 運算式本體需隱含轉換為 D 回傳型別;區塊本體需所有路徑 return 且運算式可轉換Lambda 參與泛型方法型別推斷的「資訊流動」:
static Z F<X, Y, Z>(X value, Func<X, Y> f1, Func<Y, Z> f2)
=> f2(f1(value));
double seconds = F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds);
// 推斷流程:
// 1. "1:15:30" → X = string
// 2. s: string → TimeSpan.Parse(s) → Y = TimeSpan
// 3. t: TimeSpan → t.TotalSeconds → Z = double
當多個多載僅回傳型別不同時,Lambda 的推斷回傳型別決定最佳匹配:
class ItemList<T> {
public int Sum(Func<T, int> selector) { ... }
public double Sum(Func<T, double> selector) { }
}
var details = new ItemList<Detail>();
int totalUnits = details.Sum(d => d.UnitCount); // 推斷 int → 呼叫 int 版本
double total = details.Sum(d => d.UnitPrice * d.UnitCount); // 推斷 double → 呼叫 double 版本
規則:若 Lambda 推斷回傳型別 R1 隱含轉換至 D1 回傳型別優於轉換至 D2,則 D1 勝出。
Lambda 運算式是 C# 邁向函數式程式設計的關鍵基石,掌握其型別系統互動機制,能讓你寫出更簡潔、更具表達力的程式碼。