C# - 匿名方法
C# - 从匿名方法到 Lambda 表达式
Section titled “C# - 从匿名方法到 Lambda 表达式”在 C# 中,委托(delegate)是引用方法的对象。匿名方法(anonymous methods)及其现代继任者——Lambda 表达式(lambda expressions),提供了一种强大的方式来创建可以作为委托参数传递的内联、无名方法。这对于事件处理程序、LINQ 查询和生命周期较短的辅助函数特别有用。
演变:从命名方法到内联方法
Section titled “演变:从命名方法到内联方法”让我们看看将逻辑传递给委托的演变过程,从传统的命名方法开始,逐步发展到简洁的 Lambda 表达式语法。
我们将使用内置的 Action<T> 委托,它表示一个接受一个参数且不返回任何值(void)的方法。
步骤 1:命名方法(经典方法)
Section titled “步骤 1:命名方法(经典方法)”使用委托的原始方式是为��分配一个单独的、与其签名匹配的命名方法。
using System;
// 1. 定义一个命名方法void PrintMessage(string message){ Console.WriteLine($"Named Method: {message}");}
// 2. 创建一个指向该方法的委托实例Action<string> printer = PrintMessage;
// 3. 调用委托printer("Hello, World!");匿名方法(C# 2.0)
Section titled “匿名方法(C# 2.0)”匿名方法在 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: 15Lambda 的主要优势:
Section titled “Lambda 的主要优势:”- 简洁性:语法极简,可读性高。
- 类型推断:编译器通常可以推断参数的类型,因此你可以写
(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}最佳实践与建议
Section titled “最佳实践与建议”- 优先使用 Lambda 表达式:对于任何新的 C# 代码,你都应该始终使用 Lambda 表达式(
=>),而不是旧的匿名方法语法(delegate { ... })。 - 使用内置委托:对于常见模式,优先使用泛型
Action、Func和Predicate委托,而不是定义自己的自定义委托类型。 - 保持 Lambda 简洁:Lambda 应该代表一小段、集中的逻辑。如果它变得冗长或复杂,请将其重构为一个私有命名方法,以提高可读性和可测试性。
- 理解闭包:请注意,Lambda 可以“捕获”其封闭作用域中的变量。这是一个称为闭包(closure)的强大特性,但如果理解不当,可能会对性能产生影响或导致意想不到的行为。