在.NET程序里,委托(Delegate)和事件(Event)经常一起出现,但它们扮演的角色并不相同。委托是一种类型安全的函数引用类型,事件则是建立在委托之上的发布订阅机制。理解二者差异,能让我们写出更松耦合、易维护的代码。

什么是委托
委托可以看作指向方法的变量。它定义了方法签名,任何符合该签名的方法都能赋值给委托实例。下面的代码展示了一个简单委托的声明与调用:
// 定义委托类型,接收两个int参数并返回int
public delegate int Calc(int a, int b);
class Program
{
static int Add(int x, int y)
{
return x + y;
}
static void Main()
{
// 创建委托实例并绑定方法
Calc calc = new Calc(Add);
int result = calc(3, 5);
System.Console.WriteLine(result);
}
}
多播委托
一个委托变量可以绑定多个方法,这称为多播委托。调用时会按顺序执行所有方法:
public delegate void Notify(string msg);
class Demo
{
static void A(string s) { System.Console.WriteLine("A:" + s); }
static void B(string s) { System.Console.WriteLine("B:" + s); }
static void Main()
{
Notify n = A;
n += B; // 追加方法
n("hello");
}
}
事件是对委托的封装
事件使用 event 关键字基于委托声明,限制外部只能订阅或取消订阅,不能直接触发或覆盖委托链。这保护了发布者的控制权。
public class Publisher
{
// 基于委托定义事件
public event Notify OnMessage;
public void Send(string msg)
{
// 只有类内部可以触发
if (OnMessage != null)
OnMessage(msg);
}
}
class Client
{
static void Handler(string s)
{
System.Console.WriteLine("收到:" + s);
}
static void Main()
{
Publisher p = new Publisher();
p.OnMessage += Handler; // 外部订阅
p.Send("test");
}
}
委托与事件的选择
如果只是需要把方法当参数传递,或组件内部自己管理回调,用委托即可。若要实现对象间的通知且希望禁止外部随意触发,应使用事件。常见场景如下:
- 按钮点击、状态变更等UI通知:使用事件
- 策略模式传入算法:使用委托
- 异步完成回调:可用委托或事件
注意事项
使用事件时注意内存泄漏风险,长期订阅未取消可能导致对象无法回收。另外,触发事件前务必判空,或使用空条件运算符:
// 安全触发事件
OnMessage?.Invoke("safe");
掌握这些基础后,就能在.NET项目中合理运用委托和事件,写出清晰且可扩展的逻辑。