C# Lambda 表达式

C# 中的 Lambda 表达式(Lambda Expression) 是一种简洁、函数式的语法 ,用于创建匿名函数(即没有名称的方法),通常用于初始化委托(如 ActionFunc)或表达式树(Expression Tree)。它是现代 C# 编程的核心特性之一,广泛应用于 LINQ、事件处理、异步编程和函数式风格代码中。


一、基本语法

csharp 复制代码
(参数列表) => 表达式或语句块
  • => 读作 "goes to" 或 "映射到"。
  • 左侧是参数 ,右侧是方法体

✅ 常见形式示例:

形式 示例 说明
无参 () => Console.WriteLine("Hello") 常用于 Action
单参(可省略括号) x => x * x 参数类型可推断
多参 (x, y) => x + y 必须加括号
语句块 x => { return x > 0 ? "正数" : "非正数"; } 多行逻辑用 {}
无返回值 msg => Console.WriteLine(msg) 相当于 void 方法

二、Lambda 与委托的关系

Lambda 表达式本身不是类型,但它可以隐式转换为兼容的委托类型 (如 ActionFunc)或表达式树类型Expression<T>)。

示例:赋值给 FuncAction

csharp 复制代码
// Func<int, int>:接收 int,返回 int
Func<int, int> square = x => x * x;
Console.WriteLine(square(5)); // 输出 25

// Action<string>:接收 string,无返回
Action<string> greet = name => Console.WriteLine($"Hello, {name}!");
greet("Alice"); // 输出 Hello, Alice!

🔍 编译器会根据目标类型自动推断 Lambda 的参数类型和返回类型。


三、Lambda 的核心优势

✅ 1. 简洁性

相比匿名方法或命名方法,代码更短、意图更清晰:

csharp 复制代码
// 传统方式
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
List<int> evens = numbers.FindAll(delegate(int n) { return n % 2 == 0; });

// Lambda 方式(推荐)
var evens = numbers.Where(n => n % 2 == 0).ToList();

✅ 2. 闭包(Closure)支持

Lambda 可以捕获外部作用域的变量:

csharp 复制代码
string prefix = "日志: ";
Action<string> logger = msg => Console.WriteLine(prefix + msg);
logger("程序启动"); // 输出:日志: 程序启动

编译器会自动生成一个"闭包类"来保存 prefix,确保生命周期安全。

✅ 3. 与 LINQ 无缝集成

LINQ 方法(如 WhereSelectOrderBy)大量使用 Lambda:

csharp 复制代码
var names = new[] { "Alice", "Bob", "Charlie" };
var longNames = names
    .Where(name => name.Length > 3)
    .Select(name => name.ToUpper())
    .ToArray(); // ["ALICE", "CHARLIE"]

✅ 4. 支持表达式树(Expression Tree)

当 Lambda 赋值给 Expression<Func<...>> 时,不会编译为 IL 代码,而是生成可分析的表达式树,用于 ORM(如 Entity Framework):

csharp 复制代码
Expression<Func<int, bool>> expr = x => x > 10;
// EF 可将此表达式翻译为 SQL: WHERE x > 10

四、Lambda vs 匿名方法 vs 命名方法

特性 命名方法 匿名方法 Lambda 表达式
语法简洁性 ❌ 冗长 ⭕ 中等 ✅ 极简
可读性(简单逻辑)
支持表达式树
类型推断
现代 C# 推荐度 仅复杂逻辑 基本淘汰 ✅ 首选

💡 经验法则

  • 简单逻辑 → 用 Lambda;
  • 复杂/复用逻辑 → 用命名方法;
  • 避免使用匿名方法(除非维护旧代码)。

五、高级用法示例

1. 多行 Lambda(语句块)

csharp 复制代码
Func<int, string> classify = number =>
{
    if (number < 0) return "负数";
    if (number == 0) return "零";
    return "正数";
};

2. 忽略参数(使用 _

csharp 复制代码
Action<object, EventArgs> handler = (_, __) => Console.WriteLine("Clicked!");
button.Click += handler;

3. 递归 Lambda(需先声明变量)

csharp 复制代码
Func<int, int> factorial = null;
factorial = n => n <= 1 ? 1 : n * factorial(n - 1);
Console.WriteLine(factorial(5)); // 120

六、常见内置委托类型(配合 Lambda 使用)

委托 签名 示例
Action void() () => Console.WriteLine("Run")
Action<T> void(T) x => Console.WriteLine(x)
Func<R> R() () => DateTime.Now
Func<T, R> R(T) x => x.ToString()
Predicate<T> bool(T) x => x > 0

✅ 这些类型让 Lambda 几乎无需自定义委托即可覆盖 99% 场景。


七、注意事项与陷阱

⚠️ 1. 闭包与循环变量(经典陷阱)

csharp 复制代码
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
    actions.Add(() => Console.WriteLine(i)); // 所有输出 3!
}
// 解决方案:引入局部副本
for (int i = 0; i < 3; i++)
{
    int local = i;
    actions.Add(() => Console.WriteLine(local)); // 正确输出 0,1,2
}

⚠️ 2. 性能考虑

  • Lambda 本身开销极小;
  • 但频繁创建委托对象(如在循环内)可能增加 GC 压力;
  • 表达式树比普通 Lambda 慢(因需解析树结构)。

✅ 总结

关键点 说明
是什么 创建匿名函数的简洁语法
核心符号 =>
主要用途 初始化委托、LINQ 查询、事件处理、函数式编程
优势 简洁、支持闭包、类型推断、表达式树
最佳实践 优先使用 Action/Func + Lambda,避免匿名方法

🌟 一句话记住
Lambda 表达式让 C# 拥有了"把行为当作数据传递"的能力,是写出优雅、简洁、现代 C# 代码的关键。

相关推荐
菜鸟-012 小时前
上位机---QT
开发语言·qt
Bug快跑-12 小时前
Java、C# 和 C++ 并发编程的深度比较与应用场景
java·开发语言·前端
2501_941111462 小时前
高性能计算集群部署
开发语言·c++·算法
普通网友2 小时前
模板编译期机器学习
开发语言·c++·算法
普通网友2 小时前
C++与机器学习框架
开发语言·c++·算法
普通网友2 小时前
C++安全编程指南
开发语言·c++·算法
学困昇2 小时前
C++11中的右值引用和移动语义
开发语言·c++
有梦想的攻城狮2 小时前
初识Rust语言
java·开发语言·rust
程序猿_极客3 小时前
【2025 最新】 Python 安装教程 以及 Pycharm 安装教程(超详细图文指南,附常见问题解决)
开发语言·python·pycharm·python安装以及配置