一、委托方法的 “容器”实现代码的解耦委托Delegate可以理解为方法的 “类型安全指针”它定义了方法的签名返回值 参数列表可以用来封装、传递具有相同签名的方法让方法调用和具体实现解耦。1. 委托的核心定义对具有相同返回类型和参数列表的方法进行封装是一种 “引用方法” 的数据类型。核心价值实现代码的松耦合设计让调用者不需要关心方法的具体实现只需要遵循委托的签名即可。支持多播一个委托实例可以绑定多个方法调用时会按顺序执行所有绑定的方法。2. 委托的语法与调用1定义委托语法格式非常固定// 定义委托public delegate 返回值类型 委托名(参数列表); public delegate void MyDelegate(string message);这行代码就定义了一个委托它只能接收 “无返回值、参数为 string” 的方法。2调用委托委托有两种调用方式对应同步和异步场景同步调用两种写法等价直接调用委托实例myDelegate(Hello);调用Invoke()方法myDelegate.Invoke(Hello);异步调用两种实现方式传统模式BeginInvoke()启动异步调用 EndInvoke()等待结果现代推荐使用Task封装异步委托更简洁易读。3多播委托绑定多个方法多播委托支持通过绑定多个方法-解绑方法调用时会按绑定顺序依次执行// 绑定多个方法 MyDelegate del Method1; del Method2; del Method3; // 调用时会依次执行Method1、Method2、Method3 del(多播委托测试); // 解绑方法 del - Method2;3. 委托的核心作用委托的本质就是解耦方法调用与实现举个例子你写了一个日志工具类它不需要关心谁来记录日志只需要接收一个符合签名的委托方法即可业务层可以自由实现 “写文件日志”“写数据库日志”“控制台打印日志”而日志工具类完全不用修改代码完美实现了开闭原则。二、事件基于委托的 “发布 - 订阅” 模型事件Event是在委托的基础上封装了一层 “发布 - 订阅” 的安全壳专门用于实现通知机制比如 WinForm 里的按钮点击、文本框变更本质都是事件驱动。1. 事件的核心定义事件是一种受限的委托它遵循 “发布者 - 订阅者” 模式发布者触发事件的对象只负责 “通知发生了”不关心谁订阅了事件。订阅者响应事件的对象只需要注册事件处理方法不需要关心发布者的内部实现。这种模式天然实现了模块之间的解耦是 UI 交互、状态通知的核心。2. 事件的语法实现1定义事件三种常用方式直接使用event关键字封装委托// 先定义委托 public delegate void ClickHandler(object sender, EventArgs e); // 定义事件 public event ClickHandler Click;使用预定义的EventHandler委托通用场景// 系统预定义的无参数事件委托直接使用 public event EventHandler Click;自定义事件参数使用EventHandlerTEventArgs当需要传递自定义数据时先定义EventArgs的子类再使用泛型委托// 自定义事件参数继承EventArgs public class ButtonClickEventArgs : EventArgs { public string ButtonName { get; set; } } // 定义事件 public event EventHandlerButtonClickEventArgs Click;2触发事件发布者在满足条件时触发事件需要先判断事件是否为null即是否有订阅者protected virtual void OnClick(ButtonClickEventArgs e) { // 触发事件sender是发布者自身e是事件参数 Click?.Invoke(this, e); }3订阅事件多种实现方式最常用直接用绑定方法// 订阅按钮点击事件 button.Click Button_Click; private void Button_Click(object sender, EventArgs e) { Console.WriteLine(按钮被点击了); }其他场景基类中的事件子类可以直接重写触发方法如 WinForm 的OnClick接口中定义事件让不同的类实现统一的事件通知规范自定义方法访问器用add/remove关键字自定义事件的订阅和解绑逻辑3. 事件的典型使用场景WinForm/WPF UI 交互按钮点击、文本变更、窗口加载等是事件最经典的应用场景。模块解耦比如业务逻辑层触发数据变更事件UI 层订阅并更新界面二者完全解耦。日志 / 监控 / 状态通知比如服务状态变更时触发事件通知日志模块、监控模块执行对应操作。三、事件与委托的异同别再傻傻分不清了很多人学完委托和事件还是搞不清二者的区别其实它们是 “基础与封装” 的关系核心异同点整理如下表格维度委托事件相同点1. 底层基于委托机制实现2. 都支持多播/-绑定方法3. 核心用途都是回调、通知、解耦同左不同点访问控制可以被外部直接调用任何持有委托对象的代码都能调用只能由定义事件的类内部触发外部只能通过/-订阅 / 解绑不能直接调用更安全不同点封装性只是一个方法指针类型没有额外的封装限制隐式生成私有委托字段外部无法直接访问底层委托避免被恶意调用或清空不同点接口支持不能在接口中定义委托可以在接口中定义事件比如IButton接口定义Click事件不同按钮类实现接口即可不同点使用场景更通用适合需要传递方法、异步调用、简单回调的场景专门用于发布 - 订阅的通知场景比如 UI 事件、状态变更通知简单总结一句话事件是 “安全版的委托”它限制了委托的调用权限只允许发布者内部触发外部只能订阅更适合事件驱动的场景而委托更灵活适合需要直接传递和调用方法的场景。四、实战小例子用事件实现一个简单的按钮点击结合上面的知识点写一个极简的按钮事件 Demo直观感受事件的使用using System; // 自定义按钮类 public class MyButton { // 定义事件使用泛型EventHandler public event EventHandlerstring Click; // 模拟按钮点击触发事件 public void SimulateClick() { Console.WriteLine(按钮被点击准备触发事件...); // 触发事件传递按钮名称 Click?.Invoke(this, 提交按钮); } } // 订阅者日志模块 public class LogModule { public void OnButtonClick(object sender, string buttonName) { Console.WriteLine($日志记录{buttonName} 被点击了); } } // 订阅者业务处理模块 public class BusinessModule { public void OnButtonClick(object sender, string buttonName) { Console.WriteLine($业务处理{buttonName} 点击准备提交数据); } } class Program { static void Main(string[] args) { // 发布者 MyButton button new MyButton(); // 订阅者 LogModule log new LogModule(); BusinessModule business new BusinessModule(); // 订阅事件 button.Click log.OnButtonClick; button.Click business.OnButtonClick; // 模拟点击触发所有订阅的方法 button.SimulateClick(); Console.ReadLine(); } }运行结果按钮被点击准备触发事件... 日志记录提交按钮 被点击了 业务处理提交按钮 点击准备提交数据可以看到按钮类完全不用关心有多少订阅者只需要触发事件即可订阅者也只需要实现自己的处理逻辑二者完全解耦这就是事件的魅力。五、总结委托和事件是 C# 中实现面向对象设计、事件驱动架构的核心理解它们不仅能帮你写出更解耦、更易维护的代码也是学习异步编程、框架底层比如ASP.NET Core 的管道、WPF 的依赖属性的基础。记住两个核心要点委托是 “方法的容器”负责封装和传递方法实现松耦合。事件是 “安全的委托封装”专门用于发布 - 订阅的通知场景限制了调用权限更安全。掌握了这两个概念你会发现很多以前看不懂的框架代码瞬间就通了
委托/事件
发布时间:2026/6/8 6:46:22
一、委托方法的 “容器”实现代码的解耦委托Delegate可以理解为方法的 “类型安全指针”它定义了方法的签名返回值 参数列表可以用来封装、传递具有相同签名的方法让方法调用和具体实现解耦。1. 委托的核心定义对具有相同返回类型和参数列表的方法进行封装是一种 “引用方法” 的数据类型。核心价值实现代码的松耦合设计让调用者不需要关心方法的具体实现只需要遵循委托的签名即可。支持多播一个委托实例可以绑定多个方法调用时会按顺序执行所有绑定的方法。2. 委托的语法与调用1定义委托语法格式非常固定// 定义委托public delegate 返回值类型 委托名(参数列表); public delegate void MyDelegate(string message);这行代码就定义了一个委托它只能接收 “无返回值、参数为 string” 的方法。2调用委托委托有两种调用方式对应同步和异步场景同步调用两种写法等价直接调用委托实例myDelegate(Hello);调用Invoke()方法myDelegate.Invoke(Hello);异步调用两种实现方式传统模式BeginInvoke()启动异步调用 EndInvoke()等待结果现代推荐使用Task封装异步委托更简洁易读。3多播委托绑定多个方法多播委托支持通过绑定多个方法-解绑方法调用时会按绑定顺序依次执行// 绑定多个方法 MyDelegate del Method1; del Method2; del Method3; // 调用时会依次执行Method1、Method2、Method3 del(多播委托测试); // 解绑方法 del - Method2;3. 委托的核心作用委托的本质就是解耦方法调用与实现举个例子你写了一个日志工具类它不需要关心谁来记录日志只需要接收一个符合签名的委托方法即可业务层可以自由实现 “写文件日志”“写数据库日志”“控制台打印日志”而日志工具类完全不用修改代码完美实现了开闭原则。二、事件基于委托的 “发布 - 订阅” 模型事件Event是在委托的基础上封装了一层 “发布 - 订阅” 的安全壳专门用于实现通知机制比如 WinForm 里的按钮点击、文本框变更本质都是事件驱动。1. 事件的核心定义事件是一种受限的委托它遵循 “发布者 - 订阅者” 模式发布者触发事件的对象只负责 “通知发生了”不关心谁订阅了事件。订阅者响应事件的对象只需要注册事件处理方法不需要关心发布者的内部实现。这种模式天然实现了模块之间的解耦是 UI 交互、状态通知的核心。2. 事件的语法实现1定义事件三种常用方式直接使用event关键字封装委托// 先定义委托 public delegate void ClickHandler(object sender, EventArgs e); // 定义事件 public event ClickHandler Click;使用预定义的EventHandler委托通用场景// 系统预定义的无参数事件委托直接使用 public event EventHandler Click;自定义事件参数使用EventHandlerTEventArgs当需要传递自定义数据时先定义EventArgs的子类再使用泛型委托// 自定义事件参数继承EventArgs public class ButtonClickEventArgs : EventArgs { public string ButtonName { get; set; } } // 定义事件 public event EventHandlerButtonClickEventArgs Click;2触发事件发布者在满足条件时触发事件需要先判断事件是否为null即是否有订阅者protected virtual void OnClick(ButtonClickEventArgs e) { // 触发事件sender是发布者自身e是事件参数 Click?.Invoke(this, e); }3订阅事件多种实现方式最常用直接用绑定方法// 订阅按钮点击事件 button.Click Button_Click; private void Button_Click(object sender, EventArgs e) { Console.WriteLine(按钮被点击了); }其他场景基类中的事件子类可以直接重写触发方法如 WinForm 的OnClick接口中定义事件让不同的类实现统一的事件通知规范自定义方法访问器用add/remove关键字自定义事件的订阅和解绑逻辑3. 事件的典型使用场景WinForm/WPF UI 交互按钮点击、文本变更、窗口加载等是事件最经典的应用场景。模块解耦比如业务逻辑层触发数据变更事件UI 层订阅并更新界面二者完全解耦。日志 / 监控 / 状态通知比如服务状态变更时触发事件通知日志模块、监控模块执行对应操作。三、事件与委托的异同别再傻傻分不清了很多人学完委托和事件还是搞不清二者的区别其实它们是 “基础与封装” 的关系核心异同点整理如下表格维度委托事件相同点1. 底层基于委托机制实现2. 都支持多播/-绑定方法3. 核心用途都是回调、通知、解耦同左不同点访问控制可以被外部直接调用任何持有委托对象的代码都能调用只能由定义事件的类内部触发外部只能通过/-订阅 / 解绑不能直接调用更安全不同点封装性只是一个方法指针类型没有额外的封装限制隐式生成私有委托字段外部无法直接访问底层委托避免被恶意调用或清空不同点接口支持不能在接口中定义委托可以在接口中定义事件比如IButton接口定义Click事件不同按钮类实现接口即可不同点使用场景更通用适合需要传递方法、异步调用、简单回调的场景专门用于发布 - 订阅的通知场景比如 UI 事件、状态变更通知简单总结一句话事件是 “安全版的委托”它限制了委托的调用权限只允许发布者内部触发外部只能订阅更适合事件驱动的场景而委托更灵活适合需要直接传递和调用方法的场景。四、实战小例子用事件实现一个简单的按钮点击结合上面的知识点写一个极简的按钮事件 Demo直观感受事件的使用using System; // 自定义按钮类 public class MyButton { // 定义事件使用泛型EventHandler public event EventHandlerstring Click; // 模拟按钮点击触发事件 public void SimulateClick() { Console.WriteLine(按钮被点击准备触发事件...); // 触发事件传递按钮名称 Click?.Invoke(this, 提交按钮); } } // 订阅者日志模块 public class LogModule { public void OnButtonClick(object sender, string buttonName) { Console.WriteLine($日志记录{buttonName} 被点击了); } } // 订阅者业务处理模块 public class BusinessModule { public void OnButtonClick(object sender, string buttonName) { Console.WriteLine($业务处理{buttonName} 点击准备提交数据); } } class Program { static void Main(string[] args) { // 发布者 MyButton button new MyButton(); // 订阅者 LogModule log new LogModule(); BusinessModule business new BusinessModule(); // 订阅事件 button.Click log.OnButtonClick; button.Click business.OnButtonClick; // 模拟点击触发所有订阅的方法 button.SimulateClick(); Console.ReadLine(); } }运行结果按钮被点击准备触发事件... 日志记录提交按钮 被点击了 业务处理提交按钮 点击准备提交数据可以看到按钮类完全不用关心有多少订阅者只需要触发事件即可订阅者也只需要实现自己的处理逻辑二者完全解耦这就是事件的魅力。五、总结委托和事件是 C# 中实现面向对象设计、事件驱动架构的核心理解它们不仅能帮你写出更解耦、更易维护的代码也是学习异步编程、框架底层比如ASP.NET Core 的管道、WPF 的依赖属性的基础。记住两个核心要点委托是 “方法的容器”负责封装和传递方法实现松耦合。事件是 “安全的委托封装”专门用于发布 - 订阅的通知场景限制了调用权限更安全。掌握了这两个概念你会发现很多以前看不懂的框架代码瞬间就通了