Lambda 表達式是 C# 3.0 引入的核心語法特性,它為委派建立、LINQ 查詢與函數式編程提供了簡潔有力的語法基礎。本文從匿名方法演進、語法細節、參數推斷、多參數、IL 等價性與實際應用場景深入解析。
C# 2.0 匿名方法:
button.Click += delegate { listBox.Items.Add(textBox.Text); };
C# 3.0 Lambda 表達式:
button.Click += () => listBox.Items.Add(textBox.Text);
=> 讀作 "goes to",左側為參數清單,右側為運算式或陳述式區塊。
| 形式 | 範例 | 說明 |
|---|---|---|
| 無參數 | () => 42 | 參數清單為空括號 |
| 單一參數(隱式型別) | x => x * 2 | 括號可省略 |
| 單一參數(顯式型別) | (int x) => x * 2 | 需加括號 |
| 多參數 | (x, y) => x + y | 隱式型別推斷 |
| 多參數(顯式型別) | (int x, string s) => s.Length + x | |
| 陳述式主體 | x => { Console.WriteLine(x); return x * 2; } | 需大括號與 return |
| 運算式主體 | x => x * 2 | 隱含回傳,無大括號 |
List<string> list = new List<string> { "AA", "ABC", "DEFG", "XYZ" };
// 匿名方法
var evenAnon = list.FindAll(delegate(string s) { return s.Length % 2 == 0; });
// Lambda(單一參數隱式型別)
var evenLambda = list.FindAll(s => s.Length % 2 == 0);
Dictionary<string, int> clothes = new Dictionary<string, int>
{
{ "Jeans", 20 }, { "Shirts", 15 }, { "Pajamas", 9 }, { "Shoes", 9 }
};
// 擴充方法:依鍵值對篩選
public static Dictionary<K, V> FilterBy<K, V>(
this Dictionary<K, V> dict, Func<K, V, bool> predicate)
{
var result = new Dictionary<K, V>();
foreach (var kvp in dict)
if (predicate(kvp.Key, kvp.Value))
result.Add(kvp.Key, kvp.Value);
return result;
}
// 使用多參數 Lambda
var shortage = clothes.FilterBy((name, count) => name == "Shoes" && count < 10);
if (shortage.Count > 0) Console.WriteLine("We are short of shoes");
使用 ILDASM 對比匿名方法與 Lambda 產生的 IL,發現兩者幾乎完全相同:
<Main>b__0)<>9__CachedAnonymousMethodDelegate1)結論:Lambda 表達式純粹為編譯期語法糖,不引入執行期新機制。
Lambda 表達式賦值給 Expression<TDelegate> 時,編譯器產生運算式樹而非委派:
Func<int, int> func = x => x * 2; // 委派:可執行程式碼
Expression<Func<int, int>> expr = x => x * 2; // 運算式樹:資料結構,可於執行時分析/修改/轉譯(如 LINQ to SQL)
這是 LINQ 提供者將查詢轉譯為 SQL 的關鍵基礎。
button.Click += (s, e) => DoSomething();task.ContinueWith(t => HandleResult(t.Result))Func<T, TResult> 變數與 Y-Combinator,極難維護