| 版本 | 語法 | 範例 |
|---|---|---|
| C# 1.0 | 具名委派 | delegate int Op(int x, int y); Op add = AddMethod; |
| C# 2.0 | 匿名方法 | Op add = delegate(int x, int y) { return x + y; }; |
| C# 3.0 | Lambda 表達式 | Op add = (x, y) => x + y; |
=> 讀作「goes to」,左邊是參數,右邊是運算式或陳述式區塊。
// 運算式 Lambda(單一運算式,隱含回傳)
Func add = (x, y) => x + y;
Func isEven = x => x % 2 == 0;
// 陳述式 Lambda(多行,需大括號與 return)
Func addWithLog = (x, y) {
Console.WriteLine($"Adding {x} + {y}");
return x + y;
};
// 無參數
Action greet = () => Console.WriteLine("Hello");
// 參數型別可省略(編譯器推斷),或明確指定
Func square = (int x) => x * x;
int factor = 10;
Func multiply = x => x * factor; // 捕捉 factor
factor = 20;
Console.WriteLine(multiply(5)); // 輸出 100(捕捉的是變數,非值)
注意迴圈變數捕捉陷阱(C# 5.0+ `foreach` 已修正,`for` 仍需留意)。
.NET 內建委派型別涵蓋絕大多數情境:
Func<TResult> ~ Func<T1..T16, TResult>:有回傳值Action ~ Action<T1..T16>:無回傳值Predicate<T>:Func<T, bool> 別名,常用於條件判斷
var people = new List {
new Person { Name = "小兵", Age = 23 },
new Person { Name = "青青", Age = 22 }
};
// Where: IEnumerable 擴充方法,接受 Func
var adults = people.Where(p => p.Age >= 23); // Lambda 傳遞給 predicate 參數
// Average: 接受 Func selector
double avgAge = people.Average(p => p.Age);
編譯器將 Lambda 轉換為委派實例(或運算式樹),傳遞給擴充方法。
using System.Linq.Expressions;
// 運算式樹:可在執行時分析、修改、編譯
Expression> expr = (x, y) => x + y;
var compiled = expr.Compile(); // 轉為委派
Console.WriteLine(compiled(2, 3)); // 5
// 應用:Entity Framework 將運算式樹轉譯為 SQL
var query = db.Users.Where(u => u.Age > 18); // IQueryable 使用 Expression>
| 模式 | 範例 | 說明 |
|---|---|---|
| 投影 | select p => p.Name | 轉換資料形狀 |
| 篩選 | where p => p.Age > 18 | 條件過濾 |
| 排序鍵 | orderby p => p.LastName | 指定排序依據 |
| 分組鍵 | group p by p.Department | 分組依據 |
| 副作用 | list.ForEach(item => Console.WriteLine(item)) | 慎用,違反函數純粹性 |
Lambda 表達式是 C# 函數式程式設計的核心語法糖,簡化委派撰寫、支援閉包、並為 LINQ、運算式樹、非同步程式設計提供統一的函數抽象。掌握 =>、Func/Action、閉包語意,即可駕馭現代 C# 開發。