在C#中,?Lambda表達式?是一種比匿名方法更簡潔、更靈活的語法形式,用于定義匿名函數(Anonymous Function)。它通過=>運算符實現,能夠大幅簡化委托和表達式樹的編寫,是現代C#編程中廣泛使用的核心特性之一。
核心概念?
1、何時引入?: C# 3.0 中引入,作為匿名方法的進化版本。
2?、用途?:
- 快速定義委托實例(如Func、Action)。
- 構建表達式樹(Expression Trees),支持LINQ查詢等高級場景。
- 簡化事件處理、異步編程和集合操作。
3?、特點?:
- 語法極度簡潔,支持隱式類型推斷。
- 可捕獲外部變量(閉包),與匿名方法行為一致。
- 支持兩種形式:?表達式Lambda?(單行返回值)和?語句Lambda?(多行代碼塊)。
基本語法?
1. 表達式Lambda(Expression Lambda)
(參數列表) => 表達式
單行代碼,自動返回表達式結果。
?示例?:
Func<int, int> square = x => x * x;
Console.WriteLine(square(5)); // 輸出:25
2. 語句Lambda(Statement Lambda)
(參數列表) => {// 多行代碼塊return 值; // 顯式返回(如需)
}
需使用{}包裹代碼塊,顯式使用return。
?示例?:
Action<string> log = message => {Console.WriteLine($"[{DateTime.Now}] {message}");
};
log("Hello"); // 輸出帶時間戳的消息
?示例代碼?
示例1:基本委托
// 使用內置的Func委托
Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(2, 3)); // 輸出:5// 顯式指定參數類型(當類型推斷不明確時)
Func<double, double, double> power = (double x, double y) => Math.Pow(x, y);
示例2:LINQ查詢
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0); // 過濾偶數
foreach (var num in evenNumbers) Console.WriteLine(num); // 輸出2,4
示例3:閉包與外部變量
int factor = 3;
Func<int, int> multiply = x => x * factor;
Console.WriteLine(multiply(5)); // 輸出:15factor = 10; // 閉包捕獲變量的最新值
Console.WriteLine(multiply(5)); // 輸出:50
示例4:表達式樹(高級用法)
// 將Lambda轉換為表達式樹(而非委托)
Expression<Func<int, int, int>> expr = (a, b) => a * b + 2;
var compiledExpr = expr.Compile();
Console.WriteLine(compiledExpr(3, 4)); // 輸出:14 (3*4+2)
?Lambda表達式 vs 匿名方法?
?特性? | ? Lambda表達式? | ? ?匿名方法? |
---|---|---|
?語法? | ? 使用 => 運算符 | ?使用 delegate 關鍵字 |
?參數類型推斷? | 完全支持(無需顯式聲明類型) | 需顯式聲明或依賴上下文推斷 |
?返回值? | 表達式Lambda自動返回,語句Lambda需顯式return | 必須顯式使用return |
?表達式樹支持? | 是(通過Expression) | 否 |
?代碼簡潔性? | 更簡潔 | 較冗長 |
?適用場景? | 現代C#代碼、LINQ、異步編程 | 舊版代碼(C# 2.0)、需要顯式類型聲明 |
?高級用法與注意事項?
1、閉包陷阱?:
Lambda表達式捕獲外部變量時,與匿名方法共享相同的閉包行為。在循環中直接使用循環變量可能導致意外結果:
var actions = new List<Action>();
for (int i = 0; i < 3; i++) {actions.Add(() => Console.WriteLine(i));
}
foreach (var action in actions) action(); // 輸出3次3,而非0,1,2
解決方法?:在循環內創建臨時變量:
for (int i = 0; i < 3; i++) {int temp = i;actions.Add(() => Console.WriteLine(temp)); // 輸出0,1,2
}
2、性能優化?:
- 頻繁調用的Lambda會導致重復的委托分配。可使用靜態Lambda(C# 9.0+)減少內存開銷:
Func<int, int> square = static x => x * x; // 不捕獲外部變量
- 避免在熱路徑(高頻執行代碼)中濫用閉包。
?3、與泛型方法配合?:
Lambda表達式可自動推斷泛型類型參數:
T Process<T>(T input, Func<T, T> transformer) => transformer(input);
var result = Process(10, x => x * 2); // 自動推斷T為int
4?、異步Lambda?:
Lambda表達式支持async/await語法:
Func<Task> asyncTask = async () => {await Task.Delay(1000);Console.WriteLine("Async completed");
};
?何時使用Lambda表達式??
1?、優先使用Lambda?:
- 需要簡潔的委托定義(如LINQ查詢、事件處理)。
- 構建表達式樹(如Entity Framework查詢轉換)。
- 使用現代C#特性(如異步編程、模式匹配)。
2?、選擇匿名方法?: - 維護舊版C#(< 3.0)代碼。
- 需要顯式指定參數類型且類型推斷不明確時。
總結?
Lambda表達式是C#函數式編程的核心工具,通過極簡語法和強大功能,顯著提升了代碼的可讀性和靈活性。結合閉包、表達式樹和類型推斷,它在LINQ、異步操作和高效集合處理中不可或缺。理解其底層機制(如委托分配、閉包行為)和性能影響,有助于編寫更健壯、高效的代碼。