Skip to content

C# - 匿名方法

在 C# 中,委托(delegate)是引用方法的对象。匿名方法(anonymous methods)及其现代继任者——Lambda 表达式(lambda expressions),提供了一种强大的方式来创建可以作为委托参数传递的内联、无名方法。这对于事件处理程序、LINQ 查询和生命周期较短的辅助函数特别有用。

让我们看看将逻辑传递给委托的演变过程,从传统的命名方法开始,逐步发展到简洁的 Lambda 表达式语法。

我们将使用内置的 Action<T> 委托,它表示一个接受一个参数且不返回任何值(void)的方法。

使用委托的原始方式是为��分配一个单独的、与其签名匹配的命名方法。

using System;
// 1. 定义一个命名方法
void PrintMessage(string message)
{
Console.WriteLine($"Named Method: {message}");
}
// 2. 创建一个指向该方法的委托实例
Action<string> printer = PrintMessage;
// 3. 调用委托
printer("Hello, World!");

匿名方法在 C# 2.0 中引入,它允许你使用 delegate 关键字直接在创建委托实例的地方定义方法体。这避免了创建单独的、一次性命名方法的需要。

注意:虽然功能上有效,但这种语法现在被认为是历史性的。Lambda 表达式是现代内联方法(inline methods)的首选方法。

using System;
// 使用匿名方法创建委托实例
Action<string> anonymousPrinter = delegate(string msg) {
Console.WriteLine($"Anonymous Method: {msg}");
};
// 调用委托
anonymousPrinter("This is an anonymous method.");

代码块 delegate(string msg) { ... } 就是匿名方法。编译器会根据内部的 return 语句(或 void 的缺失)推断返回类型。

Lambda 表达式(C# 3.0 及更高版本)

Section titled “Lambda 表达式(C# 3.0 及更高版本)”

Lambda 表达式在 C# 3.0 中引入,为创建匿名函数提供了更简洁、更强大的语法。它们是 LINQ 等现代 C# 特性的基石。

Lambda 表达式使用 =>(goes to)运算符定义,该运算符将左侧的输入参数与右侧的表达式或语句块分开。

using System;
// 带有语句块的 Lambda 表达式
Action<string> lambdaPrinter = (message) =>
{
Console.WriteLine($"Lambda Expression: {message}");
};
lambdaPrinter("Hello from a lambda!");
// 对于单个表达式,语法可以更简洁(表达式主体 Lambda)
Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine($"Sum: {add(5, 10)}"); // 输出: Sum: 15
  • 简洁性:语法极简,可读性高。
  • 类型推断:编译器通常可以推断参数的类型,因此你可以写 (a, b) => a + b 而不是 (int a, int b) => a + b。
  • LINQ 的动力:Lambda 是使 LINQ 的流畅查询语法成为可能的重要语言特性。

实际示例:将 Lambda 与 LINQ 结合使用

Section titled “实际示例:将 Lambda 与 LINQ 结合使用”

Lambda 表达式目前最常见的用例是与 LINQ 结合使用来查询集合。Lambda 定义了用于筛选、投影或排序数据的逻辑。

using System;
using System.Collections.Generic;
using System.Linq;
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 使用带有 'Where' 方法的 Lambda 表达式来查找所有偶数
var evenNumbers = numbers.Where(n => n % 2 == 0);
Console.WriteLine("Even numbers:");
foreach (var num in evenNumbers)
{
Console.Write($"{num} "); // 输出: 2 4 6 8 10
}
// 使用带有 'Select' 的 Lambda 将每个数字投影为其平方
var squares = numbers.Select(n => n * n);
Console.WriteLine("\n\nSquares:");
foreach (var sq in squares)
{
Console.Write($"{sq} "); // 输出: 1 4 9 16 25 36 49 64 81 100
}
  • 优先使用 Lambda 表达式:对于任何新的 C# 代码,你都应该始终使用 Lambda 表达式(=>),而不是旧的匿名方法语法(delegate { ... })。
  • 使用内置委托:对于常见模式,优先使用泛型 Action、Func 和 Predicate 委托,而不是定义自己的自定义委托类型。
  • 保持 Lambda 简洁:Lambda 应该代表一小段、集中的逻辑。如果它变得冗长或复杂,请将其重构为一个私有命名方法,以提高可读性和可测试性。
  • 理解闭包:请注意,Lambda 可以“捕获”其封闭作用域中的变量。这是一个称为闭包(closure)的强大特性,但如果理解不当,可能会对性能产生影响或导致意想不到的行为。