c#备忘录 委托和事件 (delegate & event)
在 C# 中,“事件(Event)”是委托(Delegate)的一种特殊封装机制,用于 发布者-订阅者(Publisher-Subscriber)模式 的实现。事件的主要目的是:实现对象之间的松耦合通信,让一个对象可以通知其他对象“某件事发生了”。
委托类型的事件可以在人和我地方被订阅(+=)及取消订阅(-=),然后再进行invoke操作。
delegate和event(委托和事件)
1.声明委托类型:
public delegate void DelegeteName();
2.订阅
DelegateName+=A;
3.执行
DelegetaName.Invoke();
//
methodA(()=>methodB())这样写的前提是,methodA必须接受一个委托类型的参数。
//
委托实际上是一个未实现的方法签名,需要被具体实现。
/*******************************************************************************************************************/
所以事件和委托的关系是:事件是对委托的封装,委托需要被具体实现,并通过订阅的事件被invove触发?
是的!事件(Event)本质上是对委托(Delegate)的封装,二者协同工作,共同构成了C#中的事件驱动模型。以下是更系统的关系梳理:
- 事件与委托的核心关系
角色 委托(Delegate) 事件(Event)
本质 方法的类型(定义方法签名) 对委托的封装,提供安全的订阅/触发机制
作用 存储和调用一个或多个方法 限制外部对委托的直接操作(仅允许+=/-=)
实现依赖 事件必须基于委托类型定义 事件内部通过委托存储订阅的方法 - 关键交互流程

/*******************************************************************************************************************/
步骤拆解
委托定义方法契约
public delegate void EventHandler(string msg); // 定义可被调用的方法格式
事件封装委托
public event EventHandler? Notify; // 事件基于委托类型
订阅者提供具体实现
publisher.Notify += msg => Console.WriteLine($"收到: {msg}"); // 方法需匹配委托签名
发布者触发执行
Notify?.Invoke("Hello"); // 安全调用所有订阅方法
/*******************************************************************************************************************/
3. 为什么事件要封装委托?
安全性
委托的问题:如果公开委托字段,外部可随意清空或覆盖所有订阅:
csharp
public EventHandler? Notify; // 危险!外部能直接 Notify = null;
事件的保护:通过event关键字,编译器限制外部仅能用+=和-=:
public event EventHandler? Notify; // 安全:外部只能增减订阅
语义清晰性
事件明确表示“通知”行为(如按钮点击),而委托更通用(如回调参数)。
- 完整代码验证
点击查看代码
using System;
// 1. 定义委托(方法契约)
public delegate void MessageHandler(string message);
// 2. 发布者(封装事件)
public class Publisher
{
public event MessageHandler? MessageSent; // 事件基于委托
public void SendMessage(string msg)
{
Console.WriteLine("[发布者] 发送消息中...");
MessageSent?.Invoke(msg); // 触发事件
}
}
// 3. 订阅者(实现方法)
public class Subscriber
{
public Subscriber(Publisher pub)
{
pub.MessageSent += OnMessageReceived; // 订阅事件
}
// 具体实现(严格匹配委托签名)
private void OnMessageReceived(string msg)
{
Console.WriteLine($"[订阅者] 处理消息: {msg}");
}
}
// 运行
class Program
{
static void Main()
{
var publisher = new Publisher();
var subscriber = new Subscriber(publisher);
publisher.SendMessage("Hello Events!");
}
}
[发布者] 发送消息中...
[订阅者] 处理消息: Hello Events!
/*******************************************************************************************************************/
5. 常见误区澄清
误区1:事件和委托是独立的?
事实:事件本质是委托的包装器,没有委托,事件无法存在。
误区2:事件可以自己触发?
事实:事件只能在声明它的类内部触发(Invoke),外部只能订阅。
误区3:委托只能用于事件?
事实:委托独立于事件使用(如Func/Action参数),事件只是委托的典型应用场景之一。
- 高级应用:自定义事件访问器
csharp
private EventHandler? _notify; // 实际存储委托
public event EventHandler Notify
{
add { _notify += value; } // 自定义添加逻辑
remove { _notify -= value; } // 自定义移除逻辑
}
总结
委托是基础:提供方法调用的类型安全支持。
/*******************************************************************************************************************/
事件是封装:在委托之上添加订阅/触发约束,更适合观察者模式。
协作流程:
定义委托 → 声明事件 → 订阅者实现方法 → 发布者触发 → 执行订阅逻辑
订阅者订阅事件后可以对被封装成事件的委托进行具体实现。具体的实现方法若携带了参数,可以通过发布者的.invoke()来传入参数并触发。
这种设计完美实现了松耦合——发布者无需知道谁订阅了事件,订阅者也无需知道事件何时触发!
//
2025.08.10更新
事件是基于委托(delegate)的语法糖,表示“某个动作发生时,应通知订阅者”。
//
2025.09.08更新
1.在类 A 里定义事件
public class A
{
// 定义一个事件,事件基于委托
public event Action
// 提供一个方法,用来触发事件
public void DoSomething(string msg)
{
Console.WriteLine($"A 发生了事件: {msg}");
EventA?.Invoke(msg); // 触发事件,通知所有订阅者
}
}
2. 在类 B 里订阅事件
public class B
{
private string _name;
public B(string name, A publisher)
{
_name = name;
// 订阅事件A,当A触发时会调用 HandleEvent 方法
publisher.EventA += HandleEvent;
}
// 事件触发时要执行的方法
private void HandleEvent(string msg)
{
Console.WriteLine($"{_name} 收到消息: {msg}");
}
}
3. 演示流程(Main 程序)
public class Program
{
public static void Main()
{
A publisher = new A();
// B 订阅 A 的事件
B subscriber1 = new B("订阅者1", publisher);
B subscriber2 = new B("订阅者2", publisher);
// A 触发事件
publisher.DoSomething("Hello World");
}
}
浙公网安备 33010602011771号