C#中的事件——发布者订阅者模式

2023-10-11 14:40

本文主要是介绍C#中的事件——发布者订阅者模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、发布者/订阅者模式

1. 订阅者发布者的功能:

  1. 发布者(类或结构)定义了一系列程序的其他部分可能感兴趣的事件。
  2. 订阅者(类或结构)通过向发布者提供一个方法(称为回调方法,也可以称为事件处理程序)来“注册”以获取通知。
  3. 当事件发生时,发布者“触发事件”,然后执行订阅者提交的所有事件。

 2.事件与委托的联系:

事件就像用于某种特殊用途的简单委托。事件包含了一个私有的委托。

有关事件中的私有委托的重点如下:

  1. 无法直接访问事件中的委托。
  2. 事件中的可用操作比委托要少,我们只能添加(+=)、删除(-=)或调用事件处理程序。
  3. 事件被触发时,它调用委托来依次调用调用列表中的方法。

 事件中使用的五部分代码:

  1. 委托类型声明:事件和事件处理程序必须有相同的签名和返回类型,通过委托描述。
  2. 事件处理程序声明:订阅者类中会在事件触发时执行的方法声明。
  3. 事件声明:发布者类必须声明一个订阅者类可以注册的事件成员。当声明的事件为public时称发布了事件。
  4. 事件注册:订阅者必须订阅事件才能在它被触发时得到通知。
  5. 触发事件的代码:发布者类中触发事件并导致调用注册的所有事件处理程序的代码。

二、声明事件

事件是成员。

  1. 因为事件是成员,所以必须声明在类或结构里,方法的外面。
  2. 事件成员被隐式自动初始化为null。
  3. 声明事件时需要使用event关键字。
  4. 不能使用对象创建表达式(new表达式),来创建它的对象。
  5. 它声明为public,这样其他类或结构可以在上面“注册”事件处理程序。【发布事件】
  6. 可以使用static让事件变为静态的。

(BCL专门声明了一个叫做EventHandler的委托专门用于系统事件)                          

 三、订阅事件

订阅者向事件添加事件处理程序。(必须具有和事件的委托相同的签名和返回类型)

  1. 使用“+=”运算符为事件增加事件处理程序。
  2. 事件处理程序的规范可以是实例方法名、静态方法名、匿名方法或Lambda表达式。

四、触发事件

事件成员本身只是保存了订阅的事件处理程序,需要代码触发这些事件处理程序。注意事项如下:

  1. 触发事件之前需要判断事件是否为null。
  2. 触发事件的语法和调用方法一样。

包含了发布者和订阅者的完整程序,展示了使用事件所必须的五部分,代码示例如下:

//声明委托
delegate void Handler();//发布者
class Incrementer 
{public event Handler CountedADozen;//依赖委托声明事件,(public)发布事件//触发事件的代码public void DoCount() {for (int i = 1;i < 100; i++) if( i % 12 == 0 && CountedADozen != null)CountedADozen();//每隔12个数触发一次事件}    }//订阅者
class Dozens 
{public int DozensCount { get; private set; }public Dozens(Incrementer incrementer) {DozensCount = 0;incrementer.CountedADozen += IncrementDozensCount;//订阅事件:将事件处理程序添加到事件的委托中
}//声明事件处理程序void IncrementDozensCount() {DozensCount++;}}//测试
internal class Program
{static void Main(string[] args){Incrementer incrementer = new Incrementer();Dozens dozensCount = new Dozens(incrementer);incrementer.DoCount();Console.WriteLine("事件处理程序一共被调用了:{0}次", dozensCount.DozensCount);}
}

五、标准事件的用法

1. 系统提供的事件的标准委托类型EventHandler

对于事件的使用,.NET框架提供了一个标准模式。事件使用的根本模式就是使用System命名空间声明的EventHandler委托类型。

 下面是将委托类型换为处理事件的标准委托类型EventHandler代码示例:

//发布者
class Incrementer 
{public event EventHandler CountedADozen;//使用系统提供的标准事件委托//触发事件的代码public void DoCount() {for (int i = 1;i < 100; i++) if( i % 12 == 0 && CountedADozen != null)CountedADozen(this,null);//每隔12个数触发一次事件}    }//订阅者
class Dozens 
{public int DozensCount { get; private set; }public Dozens(Incrementer incrementer) {DozensCount = 0;incrementer.CountedADozen += IncrementDozensCount;//订阅事件:将事件处理程序添加到事件的委托中
}//声明事件处理程序void IncrementDozensCount(object source,EventArgs e) {DozensCount++;}}//测试
internal class Program
{static void Main(string[] args){Incrementer incrementer = new Incrementer();Dozens dozensCount = new Dozens(incrementer);incrementer.DoCount();Console.WriteLine("事件处理程序一共被调用了:{0}次", dozensCount.DozensCount);}
}

2. 扩展EventArgs来传递数据

为了使用系统提供的标准事件的委托类型EventHandler中的第二个参数EventArgs来传递数据,需要一个派生自EventArgs的类。

代码示例如下:

    //扩展EventArgs的类用来传递数据public class IncrementEventArgs : EventArgs{ public int IterationCount { get; set; }//存储整数}//发布者class Incrementer {public event EventHandler<IncrementEventArgs> CountedADozen;//泛型委托使用自定义类//触发事件的代码public void DoCount() {//自定义类对象IncrementEventArgs args = new IncrementEventArgs();for (int i = 1; i < 100; i++)if (i % 12 == 0 && CountedADozen != null) {args.IterationCount = i;CountedADozen(this, args);//每隔12个数触发一次事件,在触发事件时传递参数}}    }//订阅者class Dozens {public int DozensCount { get; private set; }public Dozens(Incrementer incrementer) {DozensCount = 0;incrementer.CountedADozen += IncrementDozensCount;//订阅事件:将事件处理程序添加到事件的委托中}//声明事件处理程序void IncrementDozensCount(object source,IncrementEventArgs e) {Console.WriteLine("事件在第{0}次被触发,触发事件的对象:{1}",e.IterationCount,source.ToString());DozensCount++;}}//测试internal class Program{static void Main(string[] args){Incrementer incrementer = new Incrementer();Dozens dozensCount = new Dozens(incrementer);incrementer.DoCount();Console.WriteLine("事件处理程序一共被调用了:{0}次", dozensCount.DozensCount);}}

代码运行结果如下:

3.移除事件

可以将事件处理程序从事件中移除。

  1. 使用“-=”运算符将事件处理程序移除。
  2. 如果一个处理程序像事件注册了多次,那么当移除该处理程序时,将只移除列表中该处理程序的最后一个示例。

代码示例:

    //发布者class Publisher {public event EventHandler SimpleEvent;//声明事件public void RaiseTheEvent() {SimpleEvent(this, null);//触发事件 }}//订阅者class Subscriber {public void MethodA(object o, EventArgs e) { Console.WriteLine("AAA"); }//事件处理程序public void MethodB(object o, EventArgs e) { Console.WriteLine("BBB"); }//事件处理程序}//测试internal class MyTestClass{static void Main(string[] args){Publisher publisher = new Publisher();//发布者对象Subscriber subscriber = new Subscriber();//订阅者对象//订阅事件publisher.SimpleEvent += subscriber.MethodA;publisher.SimpleEvent += subscriber.MethodB;//触发事件publisher.RaiseTheEvent();Console.WriteLine("----移除事件处理程序MethodB----");//移除事件publisher.SimpleEvent -= subscriber.MethodB;//触发事件publisher.RaiseTheEvent();}}

(注:本章学习总结自《C#图解教程》)

这篇关于C#中的事件——发布者订阅者模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/weixin_66598341/article/details/129814356
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/188760

相关文章

C#代码实现解析WTGPS和BD数据

《C#代码实现解析WTGPS和BD数据》在现代的导航与定位应用中,准确解析GPS和北斗(BD)等卫星定位数据至关重要,本文将使用C#语言实现解析WTGPS和BD数据,需要的可以了解下... 目录一、代码结构概览1. 核心解析方法2. 位置信息解析3. 经纬度转换方法4. 日期和时间戳解析5. 辅助方法二、L

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

使用C#删除Excel表格中的重复行数据的代码详解

《使用C#删除Excel表格中的重复行数据的代码详解》重复行是指在Excel表格中完全相同的多行数据,删除这些重复行至关重要,因为它们不仅会干扰数据分析,还可能导致错误的决策和结论,所以本文给大家介绍... 目录简介使用工具C# 删除Excel工作表中的重复行语法工作原理实现代码C# 删除指定Excel单元

C#使用MQTTnet实现服务端与客户端的通讯的示例

《C#使用MQTTnet实现服务端与客户端的通讯的示例》本文主要介绍了C#使用MQTTnet实现服务端与客户端的通讯的示例,包括协议特性、连接管理、QoS机制和安全策略,具有一定的参考价值,感兴趣的可... 目录一、MQTT 协议简介二、MQTT 协议核心特性三、MQTTNET 库的核心功能四、服务端(BR

C#继承之里氏替换原则分析

《C#继承之里氏替换原则分析》:本文主要介绍C#继承之里氏替换原则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#里氏替换原则一.概念二.语法表现三.类型检查与转换总结C#里氏替换原则一.概念里氏替换原则是面向对象设计的基本原则之一:核心思想:所有引py

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S

C#实现访问远程硬盘的图文教程

《C#实现访问远程硬盘的图文教程》在现实场景中,我们经常用到远程桌面功能,而在某些场景下,我们需要使用类似的远程硬盘功能,这样能非常方便地操作对方电脑磁盘的目录、以及传送文件,这次我们将给出一个完整的... 目录引言一. 远程硬盘功能展示二. 远程硬盘代码实现1. 底层业务通信实现2. UI 实现三. De

C#通过进程调用外部应用的实现示例

《C#通过进程调用外部应用的实现示例》本文主要介绍了C#通过进程调用外部应用的实现示例,以WINFORM应用程序为例,在C#应用程序中调用PYTHON程序,具有一定的参考价值,感兴趣的可以了解一下... 目录窗口程序类进程信息类 系统设置类 以WINFORM应用程序为例,在C#应用程序中调用python程序

基于C#实现MQTT通信实战

《基于C#实现MQTT通信实战》MQTT消息队列遥测传输,在物联网领域应用的很广泛,它是基于Publish/Subscribe模式,具有简单易用,支持QoS,传输效率高的特点,下面我们就来看看C#实现... 目录1、连接主机2、订阅消息3、发布消息MQTT(Message Queueing Telemetr

C#特性(Attributes)和反射(Reflection)详解

《C#特性(Attributes)和反射(Reflection)详解》:本文主要介绍C#特性(Attributes)和反射(Reflection),具有很好的参考价值,希望对大家有所帮助,如有错误... 目录特性特性的定义概念目的反射定义概念目的反射的主要功能包括使用反射的基本步骤特性和反射的关系总结特性