【C#】委托与事件——1.基本概念
1. 引言
在 C# 中,“委托(Delegate)” 和 “事件(Event)” 往往是初学者感到陌生又有些抽象的概念。但它们却是实现各种回调、观察者模式和事件驱动编程的基础。如果能够熟练掌握委托与事件,不仅能让我们的代码更灵活,而且能够更好地理解许多框架内部是如何运行的。
本文将带你从零开始,先掌握 委托 的核心概念与使用方式,再理解 事件 为什么是基于委托来实现,并且在此基础上介绍如何在事件中传递额外的信息(即事件参数),帮助你建立一个对委托与事件都“了然于胸”的思维框架。
2. 什么是委托(Delegate)
2.1 概念
- 委托可以理解为一种“类型安全的函数指针”。简单来说,它可以把一个或多个方法“打包”起来,让你在需要的时候,通过委托去调用这些方法。
- 在 C# 中,我们可以把委托想象成一个“管道”或“通道”,把需要执行的方法丢进去,下次要用时,就直接执行委托即可。
2.2 定义委托
要定义一个委托类型,需要使用 delegate
关键字,并指定方法的返回值类型和参数类型。
例如:
public delegate void MyDelegate(string message);
这段代码定义了一个名为 MyDelegate
的委托,它只接受一个 string
参数,且没有返回值。凡是与此方法签名相同的方法,都可以被这个委托“存储”起来。
2.3 实例化委托
当我们想要使用这个委托时,需要创建委托实例并让它指向具体的方法:
public class Program
{
public static void ShowMessage(string message)
{
Console.WriteLine(message);
}
public static void Main()
{
// 创建委托实例并指向 ShowMessage
MyDelegate myDelegate = new MyDelegate(ShowMessage);
// 通过委托调用方法
myDelegate("Hello, World!");
// 或者使用 .Invoke 方法
myDelegate?.Invoke("Hello, World Again!");
}
}
使用
myDelegate?.Invoke(...)
可以避免在myDelegate
为空时抛出异常。
2.4 多播委托(Multicast Delegate)
- 一个 多播委托 可以包含对多个方法的引用;当调用委托时,这些方法会按照添加顺序依次执行。
- 可以通过“+”或“-”操作符来将方法加入或移除委托的调用列表。
public static void AnotherMethod(string message)
{
Console.WriteLine($"Another: {message}");
}
public static void Main()
{
MyDelegate first = new MyDelegate(ShowMessage);
MyDelegate second = new MyDelegate(AnotherMethod);
// 合并两个委托
MyDelegate combined = first + second;
// 依次执行 ShowMessage 和 AnotherMethod
combined("Hello, Multicast!");
}
3. 事件(Event)是什么
3.1 事件的基本概念
- 事件是基于委托的一种更加安全、封装性更好的机制。可以理解为:事件 = 对委托的进一步封装。
- 在事件驱动的模式里,我们常常需要一个“事件拥有者”来声明并触发事件,同时允许外部添加“事件处理方法”用来响应这个事件。
- 通过
event
关键字,C# 强制要求外部只能用+=
或-=
订阅/退订事件处理方法,无法直接替换或清空事件委托,这极大地增强了安全性。
3.2 事件的定义和触发
- 定义事件:事件本质是一个委托类型的字段,只是加上了
event
关键字以做封装。 - 订阅事件:外部只能使用
+=
来添加事件处理方法,用-=
来移除事件处理方法。 - 触发事件:通常在事件拥有者内部(类的内部)判断事件不为空后,调用
Invoke
来依次执行所有处理方法。
public class MyClass
{
// 1. 定义委托类型
public delegate void MyEventHandler(string message);
// 2. 声明事件 (基于MyEventHandler类型的event)
public event MyEventHandler MyEvent;
public void TriggerEvent(string message)
{
// 3. 触发事件,依次调用所有订阅的方法
MyEvent?.Invoke(message);
}
}
public class Program
{
public static void Main()
{
MyClass obj = new MyClass();
// 订阅事件
obj.MyEvent += MyEventHandlerMethod;
// 触发事件
obj.TriggerEvent("Hello, world!");
}
// 事件处理方法
public static void MyEventHandlerMethod(string message)
{
Console.WriteLine($"Event triggered: {message}");
}
}
3.3 关于事件参数(EventArgs)
在真实项目里,事件通常需要传递比 string message
更多的信息给订阅方。因此,C# 提供了一个 EventArgs
基类,让我们可以自定义携带各种附加数据的事件参数类。
3.3.1 使用 EventArgs
的示例
- 定义一个继承自
EventArgs
的类,在其中放置你想携带的数据。 - 定义委托时,一般采用“
object sender, EventArgs e
” 这样的标准签名,这样可以把事件触发者和自定义数据都传过去。
示例如下:
// 1. 自定义一个事件参数类,存放所需数据
public class MyCustomEventArgs : EventArgs
{
public string Message { get; set; }
public int Code { get; set; }
public MyCustomEventArgs(string message, int code)
{
Message = message;
Code = code;
}
}
public class MyClass
{
// 2. 标准事件委托:object sender, MyCustomEventArgs e
public event EventHandler<MyCustomEventArgs> MyEvent;
public void TriggerEvent(string message, int code)
{
// 3. 触发事件时,构造事件参数并调用委托
var args = new MyCustomEventArgs(message, code);
MyEvent?.Invoke(this, args);
}
}
public class Program
{
public static void Main()
{
MyClass obj = new MyClass();
// 订阅事件
obj.MyEvent += OnMyEventHandler;
// 触发事件
obj.TriggerEvent("Hello with EventArgs!", 123);
}
// 4. 事件处理方法,注意参数签名
private static void OnMyEventHandler(object sender, MyCustomEventArgs e)
{
Console.WriteLine($"Sender: {sender}, Message: {e.Message}, Code: {e.Code}");
}
}
大多数内置事件(如
Button.Click
)都是使用这种object sender, EventArgs e
的签名。
4. 事件和委托的区别与联系
-
事件是对委托的封装:
- 委托:是一种引用类型,可以指向一个或多个方法,并直接调用它们。
- 事件:在委托之上加了一层“封装”,让外界只能通过
+=
和-=
修改或移除处理方法,而不能随意替换整个委托对象,降低了误操作或恶意覆盖的风险。
-
多播功能:
- 委托 本身也支持多播,但需要手动管理。
- 事件 一般都以多播委托形式使用(多个处理方法),加减操作符则更好地管理了多播列表。
-
安全性:
- 委托 是完全开放的。外部可以
new
一个新的委托覆盖掉原来的委托实例。 - 事件 只能由类内部来触发或覆盖;类外部只能通过
+=
、-=
进行订阅或退订,大幅减少了风险。
- 委托 是完全开放的。外部可以
-
使用场景:
- 委托 更适合需要把某个“回调方法”当参数传来传去的场合;或需要灵活直接调用多个方法的场合。
- 事件 则是发布-订阅模式的首选,用来做组件间的通知、GUI 交互、消息推送等。
5. 总结
- 委托:是“方法引用”的集合,可被当成参数传递,也可多播。
- 事件:是基于委托的更安全封装,实现了典型的“发布-订阅”模式,外部只能订阅或取消订阅,不能随意修改事件本身。
- 事件参数:通过
EventArgs
传递更丰富的信息,是实际项目中常用的做法。
通过委托与事件,你可以在 C# 中构建更灵活、更安全的回调机制和事件驱动程序。希望这篇文章能帮你打通概念中的阻塞,让你对委托与事件都更加得心应手!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤