// 定義委派型別
public delegate bool IntFilter(int i);
public class Common
{
public static int[] FilterArray(int[] source, IntFilter filter)
{
var list = new List();
foreach (int i in source)
if (filter(i)) list.Add(i);
return list.ToArray();
}
}
// 算法實作為獨立命名方法
public class Algorithms
{
public static bool IsOdd(int i) => (i & 1) == 1;
public static bool IsEven(int i) => (i & 1) == 0;
public static bool GreaterThan5(int i) => i > 5;
}
// 呼叫端
int[] numbers = { 1,2,3,4,5,6,7,8,9,10 };
var odds = Common.FilterArray(numbers, Algorithms.IsOdd); // 傳遞方法群組
// 內聯定義算法,無需獨立方法
var odds = Common.FilterArray(numbers, delegate(int i) { return (i & 1) == 1; });
// 捕獲外部變數 (閉包)
int threshold = 5;
var greater = Common.FilterArray(numbers, delegate(int i) { return i > threshold; });
// 完整語法:(參數) => { 陳述式; return 結果; }
var odds = Common.FilterArray(numbers, (int i) => { return (i & 1) == 1; });
// 單一運算式簡寫:隱含 return、類型推斷
var odds = Common.FilterArray(numbers, i => (i & 1) == 1);
// 多參數需括號
var compare = (int x, int y) => x == y;
// 無參數
var getTime = () => DateTime.Now;
// 陳述式主體 (多行)
var complex = (int x, int y) =>
{
if (x > y) return x;
return y;
};
| 形式 | 範例 | 說明 |
|---|---|---|
| 單參數隱含類型 | x => x * 2 | 最常用 |
| 單參數顯式類型 | (int x) => x * 2 | 需明確類型時 |
| 多參數 | (x, y) => x + y | 括號必要 |
| 無參數 | () => "Hello" | 空括號必要 |
| 陳述式主體 | x => { Console.WriteLine(x); return x*2; } | 大括號 + 明確 return |
| 運算式主體 | x => x * 2 | 隱含 return,無大括號 |
| 異步 Lambda | async x => await Fetch(x) | C# 5.0+ |
public void DemoCapture()
{
int factor = 10;
Func multiply = x => x * factor; // 捕獲 factor
factor = 20; // 修改外部變數
Console.WriteLine(multiply(5)); // 輸出 100 (捕獲的是變數,非值!)
// 迴圈陷阱
var funcs = new List>();
for (int i = 0; i < 3; i++)
{
int captured = i; // 關鍵:建立區域副本
funcs.Add(() => captured);
}
// 輸出 0, 1, 2 (正確)
// 若直接捕獲 i,輸出 3, 3, 3 (錯誤)
}
Lambda 表達式是 LINQ 標準查詢運算子的核心參數型別 (Func<T, bool>, Func<T, TResult>)。
var numbers = Enumerable.Range(1, 100);
var result = numbers
.Where(n => n % 2 == 0) // 篩選偶數
.Select(n => n * n) // 投影平方
.Take(10) // 取前 10
.OrderByDescending(n => n) // 降序
.ToList();
// 方法語法 vs 查詢語法
var q = from n in numbers
where n % 2 == 0
select n * n; // 編譯器轉換為 Where/Select Lambda
| 委派型別 | 參數 | 回傳 | Lambda 範例 |
|---|---|---|---|
Action | 無 | void | () => Console.WriteLine("Hi") |
Action<T> | 1 | void | x => Console.WriteLine(x) |
Func<TResult> | 無 | TResult | () => 42 |
Func<T, TResult> | 1 | TResult | x => x.ToString() |
Func<T1, T2, TResult> | 2 | TResult | (x, y) => x + y |
Predicate<T> | 1 | bool | x => x > 0 |
using System.Linq.Expressions;
// Lambda 編譯為委派 (執行碼)
Func func = x => x * 2;
int result = func(5); // 10
// Lambda 編譯為表達式樹 (資料結構,可分析/轉換)
Expression> expr = x => x * 2;
// 應用:Entity Framework 將表達式樹翻譯為 SQL
// 應用:動態建構查詢、序列化規則引擎
// 手動建構表達式樹
var param = Expression.Parameter(typeof(int), "x");
var body = Expression.Multiply(param, Expression.Constant(2));
var lambda = Expression.Lambda>(body, param);
var compiled = lambda.Compile(); // 回到委派
Lambda 表達式是 C# 函數式程式設計的基石,極大簡化了委派使用語法,配合 LINQ 實現聲明式資料處理。理解其閉包捕獲語意、類型推斷規則與表達式樹雙重身分,是掌握現代 C# 開發的關鍵。