Skip to content

C# 委托与事件深度解析 ​

委托和事件是 .NET 开发中极其重要的概念,也是理解很多高级特性(如 LINQ、异步编程、观察者模式)的基础。

1. 委托 (Delegate) ​

1.1 什么是委托? ​

委托是持有一个或多个方法引用的对象。它类似于 C++ 中的函数指针,但是它是类型安全且面向对象的。

委托定义了方法的“签名”(参数类型和返回类型)。

csharp
// 定义一个委托类型
public delegate void GreetingDelegate(string name);

// 使用委托
public static void EnglishGreeting(string name) => Console.WriteLine($"Hello, {name}");
public static void ChineseGreeting(string name) => Console.WriteLine($"你好, {name}");

static void Main()
{
    GreetingDelegate del = EnglishGreeting;
    del("Liker"); // 输出: Hello, Liker
}

1.2 为什么使用委托? ​

  • 将方法作为参数传递:使得程序具有更好的扩展性,避免大量的 if-else 或 switch 逻辑。
  • 解耦:调用方不需要知道具体执行的是哪个方法,只需要按照约定的签名调用即可。

1.3 多播委托 (Multicast Delegate) ​

一个委托变量可以绑定多个方法。使用 += 绑定方法,使用 -= 注销方法。

csharp
GreetingDelegate del = EnglishGreeting;
del += ChineseGreeting;
del("Liker"); // 依次调用 EnglishGreeting 和 ChineseGreeting

2. 事件 (Event) ​

2.1 事件的由来 ​

事件是对委托的封装。

  • 如果直接使用 public delegate 变量,外部可以直接赋值(覆盖掉已有的方法绑定),这破坏了封装性。
  • 事件限制了外部只能使用 += 和 -=,而不能直接赋值或在外部触发。

2.2 声明与使用 ​

csharp
public class Heater
{
    // 声明委托
    public delegate void BoiledHandler(int temperature);
    // 声明事件
    public event BoiledHandler Boiled;

    public void BoilWater()
    {
        // ... 烧水逻辑 ...
        Boiled?.Invoke(95); // 只能在类的内部触发
    }
}

3. Observer (观察者) 设计模式 ​

委托和事件是实现观察者模式的天然工具。

  • Subject (监视对象):发布事件的类(如热水器)。
  • Observer (监视者):订阅事件的类(如报警器、显示器)。

这种模式实现了对象间的松耦合:热水器不需要知道谁在监视它,它只负责在水开时发出信号。


4. .NET 框架中的规范 ​

.NET 定义了一套标准的事件处理模式:

  1. 委托名称:以 EventHandler 结尾。
  2. 委托签名:返回值为 void,接受两个参数:object sender (发布者) 和 EventArgs e (事件数据)。
  3. 事件数据:继承自 EventArgs。
csharp
public class BoiledEventArgs : EventArgs
{
    public int Temperature { get; }
    public BoiledEventArgs(int temp) => Temperature = temp;
}

public delegate void BoiledEventHandler(object sender, BoiledEventArgs e);
public event BoiledEventHandler Boiled;

5. 委托与异步调用 ​

在 async/await 普及之前,委托的 BeginInvoke 和 EndInvoke 是实现异步编程的主要手段。

  • BeginInvoke: 从线程池中抓取一个线程异步执行方法。
  • EndInvoke: 获取异步方法的返回值,如果任务未完成则阻塞等待。
  • AsyncCallback: 任务完成后的回调通知。

💡 提示:在现代 .NET 开发中,建议优先使用 Task 和 async/await 代替委托的异步调用。


6. 总结 ​

  • 委托 是类型安全的方法指针。
  • 事件 是委托的保护壳,提供了更好的封装性。
  • 观察者模式 通过事件实现了组件间的松耦合。
  • 异步委托 是历史悠久的并行编程方式,现在多被 Task 取代。

7. 参考资料 ​

方舟 · Ark