在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、异步操作和高效集合处理中不可或缺。理解其底层机制(如委托分配、闭包行为)和性能影响,有助于编写更健壮、高效的代码。