谈一谈C#的事件

C#中事件基于委托,要理解事件要先理解委托,如果觉得自己关于委托不是很了解可以看看我前面写委托的文章

事件基于委托,是一种功能受限的委托,为委托提供了一种发布/订阅机制

使用委托时,一般会出现两种角色:广播者(发布者)和订阅者,这是一个非常常见的模型

依然是用一个非常典型的例子来说明事件,举一个具体的例子就是微信公众号,广播者就是公众号管理员,订阅者就是普通用户。

using System;

class Program
{
static void Main(string[] args)
{
公众号 actionNet = new 公众号();
用户 m = new 用户(); // 订阅事件
actionNet.Published += m.ReceiveMessage; // 执行动作,动作中包含广播行为
actionNet.Publish();
}
} // 定义“发布”委托
public delegate void PublishHandler(); // 特别提醒:为了便于理解,我使用了中文类名,在真实项目中,请勿使用中文关键字
class 公众号
{
public event PublishHandler Published; public void Publish()
{
Console.WriteLine("我是ActionNet,我发布了一条消息"); // 使用了null判断运算符,如果Published为空则不执行后面相关调用
// Published.Invoke()与Published()相同,都是执行委托/事件,后者是前者的简写
// 这条语句就是广播行为
Published?.Invoke();
}
} class 用户
{
public void ReceiveMessage()
{
Console.WriteLine("有一条新的公众号消息到达,请查阅!!!");
}
}

首先广播者,这里的广播者是公众号类,首先定义了一个事件,然后定义了一个方法,在这个方法中触发事件,广播给所有订阅者

订阅者是用户类,只有一个方法

回到Main函数,首先实例化了一个公众号对象和用户对象

然后使用+=将订阅者的方法注册到事件中(事件只能使用+=和-=注册和撤销订阅,后面会讲)

最后是广播者调用了触发事件的方法,向所有订阅者广播(由事件委托执行订阅者注册到事件中的方法)

标准事件模式

.Net Framwork为事件编程定义了一个标准模式,目的是保持框架和用户代码的一致性,核心是System.EventArgs类,但是在.Net Core中并不再要求System.EventArgs类,这个下一节讲

在.Net Framework的标准事件模式中,需要

  • 一个类,继承自EventArgs,类名根据包含的信息来命名,以EventArgs结尾

  • 事件所需的委托(框架定义了名为EventHandler<T>的泛型委托,满足下面的要求,且可以接受所有类型)

    • 委托必须以void作为返回值
    • 委托必须接受两个参数,第一个参数是object类型,第二个参数则是EventArgs的子类。第一个参数表明了事件的广播者,第二个参数则包含了需要传递的额外信息
    • 委托的名称必须以EventHandler结尾
  • 一个protected的虚方法来触发事件,方法名必须和事件名称一致,以On为前缀,并接受唯一的EventArgs参数

下面我们来看前面的例子改写成标准模式的样子

// 带参数的标准模式
using System; class Program
{
static void Main(string[] args)
{
公众号 actionNet = new 公众号();
用户 m = new 用户(); // 订阅事件
actionNet.Published += m.ReceiveMessage; // 执行动作,动作中包含广播行为
actionNet.Publish("人生若只如初见");
}
} // 定义需要传递的额外信息类
class MessageEventArgs : EventArgs
{
public MessageEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
} // 定义事件的委托,这个委托.Net Framework定义好了的,其实不必再定义,在后面迁移到.Net Core时也改动更少
// public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs; // 特别提醒:为了便于理解,我使用了中文类名,在真实项目中,请勿使用中文关键字
class 公众号
{
public event EventHandler<MessageEventArgs> Published; protected virtual void OnPublished(MessageEventArgs e)
{
Console.WriteLine("我是ActionNet,我发布了一条消息"); // this表明事件的广播者是这个类,e是需要传递的额外信息
Published?.Invoke(this,e);
} public void Publish(string content)
{
OnPublished(new MessageEventArgs(content));
}
} class 用户
{
public void ReceiveMessage(object sender,MessageEventArgs e)
{
Console.WriteLine("有一条新的公众号消息到达,请查阅!!!");
Console.WriteLine($"消息来自:{sender}");
Console.WriteLine(e.Message);
}
}
// 不需要额外信息的标准模式
using System; class Program
{
static void Main(string[] args)
{
公众号 actionNet = new 公众号();
用户 m = new 用户(); // 订阅事件
actionNet.Published += m.ReceiveMessage; // 执行动作,动作中包含广播行为
actionNet.Publish("人生若只如初见");
}
} // 不需要用以传递信息的额外信息类 // 定义事件的委托,这个委托.Net Framework定义好了的,其实不必再定义,在后面迁移到.Net Core时也改动更少
// public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs; // 特别提醒:为了便于理解,我使用了中文类名,在真实项目中,请勿使用中文关键字
class 公众号
{
// 使用非泛型的EventHandler委托类型
public event EventHandler Published; // 触发事件的方法,直接接收EventArgs类型参数
protected virtual void OnPublished(EventArgs e)
{
Console.WriteLine("我是ActionNet,我发布了一条消息"); // this表明事件的广播者是这个类,e是需要传递的额外信息
Published?.Invoke(this,e);
} public void Publish(string content)
{
//无需额外的信息,则无需创建EventArgs实例,直接返回空
OnPublished(EventArgs.Empty);
}
} class 用户
{
public void ReceiveMessage(object sender,EventArgs e)
{
Console.WriteLine("有一条新的公众号消息到达,请查阅!!!");
Console.WriteLine($"消息来自:{sender}");
}
}

.Net Core的标准事件模式

.NET Core 的标准事件模式较为宽松。 在此版本中,EventHandler<TEventArgs> 定义不再要求 TEventArgs 必须是派生自 System.EventArgs 的类

这个可以看一下官方文档,后面有机会我再更新

事件相对于委托的限制

事件是一种功能受限的委托,具体受限的地方是事件只能使用+=-=,相比于委托少了=(这是其中之一,还理解得不是很透彻,后面再补)

拿前面的代码actionNet.Published += m.ReceiveMessage;这一句是添加订阅,如果不需要了可以使用-=删除订阅,但是不能使用actionNet.Published = null,这样的代码更加健壮

谈一谈C#的事件的更多相关文章

  1. 谈一谈iOS事件的产生和传递

    谈一谈iOS事件的产生和传递 1.事件的产生 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中. UIApplication会从事件队列中取出最前面的事件,并将事件 ...

  2. 谈一谈Java8的函数式编程(二) --Java8中的流

    流与集合    众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...

  3. 谈一谈泛型(Generic)

    谈一谈泛型 首先,泛型是C#2出现的.这也是C#2一个重要的新特性.泛型的好处之一就是在编译时执行更多的检查. 泛型类型和类型参数 ​ 泛型的两种形式:泛型类型( 包括类.接口.委托和结构 没有泛型枚 ...

  4. 从一张图开始,谈一谈.NET Core和前后端技术的演进之路

    从一张图开始,谈一谈.NET Core和前后端技术的演进之路 邹溪源,李文强,来自长沙.NET技术社区 一张图 2019年3月10日,在长沙.NET 技术社区组织的技术沙龙<.NET Core和 ...

  5. 谈一谈Elasticsearch的集群部署

      Elasticsearch天生就支持分布式部署,通过集群部署可以提高系统的可用性.本文重点谈一谈Elasticsearch的集群节点相关问题,搞清楚这些是进行Elasticsearch集群部署和拓 ...

  6. 谈一谈对MySQL InnoDB的认识及数据库事物处理的隔离级别

    介绍: InnoDB引擎是MySQL数据库的一个重要的存储引擎,和其他存储引擎相比,InnoDB引擎的优点是支持兼容ACID的事务(类似于PostgreSQL),以及参数完整性(有外键)等.现在Inn ...

  7. 谈一谈APP版本号问题

    如题:谈一谈APP版本号问题 为什么要谈这个问题,周五晚上11~12点,被微信点名,说APP有错,无效的版本号,商城无法下单.我正在准备收拾东西,周末回老家,结果看到这样问题,菊花一紧.我擦,我刚加的 ...

  8. 谈一谈深度学习之semantic Segmentation

    上一次发博客已经是9月份的事了....这段时间公司的事实在是多,有写博客的时间都拿去看paper了..正好春节回来写点东西,也正好对这段时间做一个总结. 首先当然还是好好说点这段时间的主要工作:语义分 ...

  9. 蓝的成长记——追逐DBA(5):不谈技术谈业务,恼人的应用系统

    ***************************************声明*************************************** 个人在oracle路上的成长记录,当中 ...

随机推荐

  1. 牛客编程巅峰赛S1第5场 - 青铜&白银 C.排队 (优先队列,归并排序)

    题意:有\(m\)个窗口,\(n\)个人排队,每个人都有各自的办理时间,只有办理完成窗口才能空出来,后面的人开始办理,求有多少人比后面的人开始办理的早但完成的晚. 题解:我们可以用优先队列来模拟办理, ...

  2. 洛谷 P5837 [USACO19DEC]Milk Pumping G (单源最短路,dijkstra)

    题意:有一\(n\)个点,\(m\)条边的双向图,每条边都有花费和流量,求从\(1\)~\(n\)的路径中,求\(max\frac{min(f)}{\sum c}\). 题解:对于c,一定是单源最短路 ...

  3. 13. 从0学ARM-Cortex-A9 RTC裸机程序编写

    一.RTC RTC(Real-Time Clock) 实时时钟. RTC是集成电路,通常称为时钟芯片.在一个嵌入式系统中,通常采用RTC来提供可靠的系统时间,包括时分秒和年月日等,而且要求在系统处于关 ...

  4. C# Dictionary(字典)源码解析&效率分析

    通过查阅网上相关资料和查看微软源码,我对Dictionary有了更深的理解. Dictionary,翻译为中文是字典,通过查看源码发现,它真的内部结构真的和平时用的字典思想一样. 我们平时用的字典主要 ...

  5. XV6学习(16)Lab net: Network stack

    最后一个实验了,代码在Github上. 这一个实验其实挺简单的,就是要实现网卡的e1000_transmit和e1000_recv函数.不过看以前的实验好像还要实现上层socket相关的代码,今年就只 ...

  6. GoAccess 监控工具

    GoAccess 基本概述 简易的统计访问量的软件,官方安装教程 GoAccess 安装 # 下载包 [root@web01 ~]# wget http://tar.goaccess.io/goacc ...

  7. leetcode347 python

    通过维护最小堆排序,使用heapq模块 一般使用规则:创建列表 heap = [] 函 数                                                        ...

  8. appveyor build failed --

    在 https://www.cnblogs.com/lqerio/p/11117498.html 使用了appveyor 进行 hexo 博客的版本控制持续集成. 今天push 到 github的 r ...

  9. codeforces 1059C. Sequence Transformation【构造】

    题目:戳这里 题意:有1,2,3...n这n个数,求一次这些数的gcd,删去一个数,直到剩下一个数为止.输出这n个gcd的最大字典序. 解题思路:一开始的gcd肯定是1,要让字典序最大,我们可以想到下 ...

  10. Mysql(三)------事务的特性、事务并发、事务读一致性问题

    1 什么是数据库的事务? 1.1 事务的典型场景 在项目里面,什么地方会开启事务,或者配置了事务?无论是在方法上加注解,还 是配置切面 <tx:advice id="txAdvice& ...