C# - 委托
C# - 委托与 Lambda 表达式
Section titled “C# - 委托与 Lambda 表达式”C# 中的**委托(delegate)**是一种安全封装方法的类型,类似于 C++ 中的函数指针。它充当对具有特定参数列表和返回类型的方法的引用。委托是事件、回调和 LINQ 的基础。
虽然您可以声明自定义委托类型,但现代 C# 开发主要依赖内置的泛型委托(Func、Action、Predicate)和Lambda 表达式,以实现更简洁和强大的语法。
现代方法:泛型委托
Section titled “现代方法:泛型委托”.NET 库提供了内置的泛型委托类型,涵盖了大多数常见场景,从而无需声明自定义委托。
| 委托 | 描述 | 示例 |
|---|---|---|
Func<T, TResult> | 表示一个接受一个或多个输入参数(T)并返回一个值(TResult)的方法。有最多支持 16 个输入参数的重载。 | Func<int, int, int> add; // 接收两个 int,返回一个 int。 |
Action<T> | 表示一个接受一个或多个输入参数(T)但不返回任何值(void)的方法。 | Action<string> print; // 接收一个 string,不返回任何值(void)。 |
Predicate<T> | Func 的一个特化版本,它接受一个参数(T)并始终返回一个 bool 值。它通常用于测试条件。 | Predicate<int> isEven; // 接收一个 int,返回一个 bool。 |
Lambda 表达式:简洁的力量
Section titled “Lambda 表达式:简洁的力量”一个**Lambda 表达式(lambda expression)**是一个匿名函数,可用于创建委托或表达式树类型。它提供了一种编写方法的简写方式,而无需完整的 方法声明。
// Lambda 语法:(输入参数) => { 表达式或语句块 }
// 示例 1:一个 Func<>,用于添加两个数字Func<int, int, int> add = (x, y) => x + y;int sum = add(10, 5);Console.WriteLine($"Sum: {sum}"); // 输出:Sum: 15
// 示例 2:一个 Action<>,用于打印消息Action<string> greet = name => Console.WriteLine($"Hello, {name}!");greet("World"); // 输出:Hello, World!
// 示例 3:一个 Predicate<>,用于检查数字是否为正数Predicate<int> isPositive = n => n > 0;Console.WriteLine($"Is -5 positive? {isPositive(-5)}"); // 输出:Is -5 positive? False委托有一个强大的特性,称为多播(multicasting),即单个委托可以引用并调用多个方法。您可以使用 + 和 -(或 += 和 -=)运算符向委托的调用列表添加或移除方法。
Action<string> logger;
Action<string> logToConsole = message => Console.WriteLine($"CONSOLE: {message}");Action<string> logToFile = message => System.IO.File.AppendAllText("log.txt", $"{message}\n");
// 将两个方法组合成一个委托实例logger = logToConsole;logger += logToFile;
// 调用 'logger' 现在将同时调用两个方法logger("System startup complete.");
// 移除一个方法logger -= logToConsole;logger("User logged in."); // 这将只写入到文件中
Console.WriteLine("Logging complete. Check log.txt");当您运行此代码时,“System startup complete.”会同时打印到控制台和日志文件。“User logged in.”则只写入到日志文件。
委托的关键实际应用
Section titled “委托的关键实际应用”1. LINQ (语言集成查询)
Section titled “1. LINQ (语言集成查询)”委托是 LINQ 的支柱。像 Where、Select 和 OrderBy 这样的方法都接受委托(通常是 Lambda 表达式)来执行它们的操作。
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 'Where' 接收 Func<int, bool>(或 Predicate<int>)var evenNumbers = numbers.Where(n => n % 2 == 0);
// 'Select' 接收 Func<int, TResult>var squaredNumbers = evenNumbers.Select(n => n * n);
Console.WriteLine(string.Join(", ", squaredNumbers)); // 输出:4, 16, 36, 64, 1002. 事件处理
Section titled “2. 事件处理”C# 中的事件使用委托来定义事件处理程序的签名。当事件触发时,所有注册的处理方法都会被调用。
public class Button{ // 事件基于 Action 委托 public event Action? Clicked;
public void SimulateClick() { Console.WriteLine("Button was clicked!"); Clicked?.Invoke(); // 安全地调用委托 }}
var myButton = new Button();
// 使用 Lambda 表达式订阅事件myButton.Clicked += () => Console.WriteLine("Event handler: Responding to click!");myButton.Clicked += () => Console.WriteLine("Another handler: Updating UI...");
myButton.SimulateClick();当上述代码被编译和执行时,会产生以下结果:
Button was clicked!Event handler: Responding to click!Another handler: Updating UI...