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#中的事件驱动模型。以下是更系统的关系梳理:

  1. 事件与委托的核心关系
    角色 委托(Delegate) 事件(Event)
    本质 方法的类型(定义方法签名) 对委托的封装,提供安全的订阅/触发机制
    作用 存储和调用一个或多个方法 限制外部对委托的直接操作(仅允许+=/-=)
    实现依赖 事件必须基于委托类型定义 事件内部通过委托存储订阅的方法
  2. 关键交互流程

image

/*******************************************************************************************************************/
步骤拆解
委托定义方法契约

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; // 安全:外部只能增减订阅
语义清晰性
事件明确表示“通知”行为(如按钮点击),而委托更通用(如回调参数)。

  1. 完整代码验证
点击查看代码
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参数),事件只是委托的典型应用场景之一。

  1. 高级应用:自定义事件访问器
    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? EventA;

// 提供一个方法,用来触发事件
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");
}

}

posted @ 2025-08-08 11:11  rhhLiu  阅读(208)  评论(0)    收藏  举报