C#_Events(事件_理论篇)
在本篇,我们主要学习并理解以下几个方面:
.Net Framework 命名时的约定俗成
- 如果这个方法是触发事件的方法,或者事件本身,需要在命名前方加上On来作为前缀。
- 如果一个类,是用来传递事件消息(EventArgs)的,应该命名为[XX事件 + EventArgs],EventArgs全称EventArguments。一般这个类会继承自EventArgs这个基类。
- 为了事件而声名的委托类型,.Net又规定了,我们最好在委托类型的后面加上EventHandler来作为后缀。
什么是事件
- 在微软的C#编程语言指导中的解释是:
- 事件有能力使一个类或者对象去通知其他类和对象,当一些事情发生时。
- 自身理解:
- 当《空洞骑士—丝之歌》预告发布时,预告发布是一个事件,这个事件会通知不同的对象,比如玩家,营销号,游戏平台等等。
- 总结一下就是:
- 能够给“发生”作为主语的名词,就是事件。
事件的定义:
- 事件,是一个类型成员。
- 凡是事件,都隶属于某一个主题,如果没有丝之歌,就不会有预告发布这个事件发生。
- 面向对象编程,也就是对现实世界的一个模拟,在现实生活的某一个事件,他是必须基于某个主体的。
- 比如上述的预告发布这个事件,是基于游戏主体的。所以在程序世界当中,抽象出来之后事件它就必定会是一个对象,类的成员。
- 事件可以“发生”,通知别人,发生后的效果,才是事件的功能。
- 事件是一种具有通知能力的成员。所以事件的核心功能就是通知。
- 题外话:
- 一个类当中最重要的三个成员:
- 属性Properties
- 方法Methods
- 事件Events
什么是通知
拿生活中最常见的例子来举例,你在刷朋友圈,看见了你的女神发了一条分手的消息。抽象一下就是:作为主体的女神(也就是一个类),它具备了[分手]这个事件成员。
当她[分手]这个事件发生之后,她通过朋友圈,来通知关注这则消息的一些潜在人群。而这些潜在人群,一定是关注了她分手这个事件。分手这个事件,让女神具备了通知关注者的能力。
你们也就是我们,等于收到了女神[分手]这个事件的通知,我们这时可以采取行动了。更进一步来说,伴随着事件的发生,在发生的时候,必定会产生一些和事情本身相关的数据。我们把与事件本身相关的数据,也就是我们所说的消息叫做事件参数:EventArgs。以朋友圈为例,当女神发这个朋友圈的时候,那她必然会伴随着一些其他消息,比如,地址,有趣的图片,或者是否@你等等。
站在女神这个类的角度上,她在完成了通知关注者的同时把相关的信息也一并发送给了事件的关注者。也就是我们,站在关注者的角度,我们除了收到通知之外,还受到了经由事件发送过来的消息。
- 这里的消息具体是什么:
- 微软把这些经由事件发送过来的消息与事件本省相关的数据,也就是我们所说的消息叫做事件参数。
但是这个事件参数有什么用处呢,我们接受到这个事件参数后,会根据事件参数里的内容采取相应的行动。
微软把通过通知和事件参数,而采取行动的行为叫做相应事件或者处理事件,而处理事件时所具体做的事情,我们叫做事件处理器:EventHandler。
抽象成程序世界的话,就是如果一个事件发生了,别的类要做出响应,那么别的类(事件响应者)必定回去调用它的一个方法(事件处理器),而我们把这个方法就叫做事件处理器。
这里已经可以差不多知道[事件模型]的五个组成部分了:
- 事件的拥有者
- 事件
- 事件的响应者
- 事件处理器
- 事件订阅(+=操作符)
比如玩家去商城购买东西:
事件模型 | 类比对象 |
---|---|
事件的拥有者 | 玩家 |
事件 | 买东西 |
事件的响应者 | 商店老板 |
事件处理器 | 方法(背包中物品的添加) |
事件订阅 | += |
这里在完善一下事件的核心功能的定义:将事件的事件参数,也就是事件的相关信息,通知给那些订阅了这个事件的人们。
事件模型
五个步骤
- 我(类)要有一个事件(成员)
- 一群别的类关心,订阅我的事件。
- 我的事件发生了。
- 关心的类们被一次性通知到。
- 被通知到的人,拿着事件参数,做出响应。
五个组成部分
- 事件的拥有者
- 事件
- 事件的响应者
- 事件处理器
- 事件订阅(+=操作符)
- 事件的拥有者:
- 英文是Event Publisher/Event Source 直译就是事件的源头。
事件的拥有者一定是一个类(或者说是对象),谁拥有事件,谁就是事件的拥有者。
如果用刘老师的话来说就是:皮之不存,毛将焉附。 - 事件:
- 是一种让事件的拥有者具有通知能力的成员。
事件本身不会主动发生,是满足一定条件下的被动的时候。 比如说:玩家阵亡,玩家会主动阵亡嘛,不会,是在触发一定条件下才会阵亡。
站在现实生活中呢,事件就是一个用来通知别人的工具。而工具总是被动的,需要有人去使用,才能发挥出它的效果。如果你不去用它,那么它就会放在那里什么都不做。
总结一下:事件本身是不会主动通知别的对象,类的。 - 事件响应者:
- 订阅事件的类,对象们。
- 事件处理器:
- 事件响应者处理事件的方法。本质是回调。
- 事件订阅:
- 虽然是一个简单的操作符,却解决了三大核心问题:
- 事件发生后,通知的一定是[订阅]了事件的对象们。
- 事件处理器和事件的关系。(本质就是事件处理器的返回值和参标是否和事件的委托类型一致)
- C#规定:
- 用于订阅事件的这个事件处理器,必须和事件遵循同一个约定。也就是事件处理器和事件必须是相匹配的。
- 事件的响应者具体拿什么方法来处理事件。一个事件响应者,可能有很多个满足约定的事件处理器,至于我们要拿那个方法来处理这个事件呢,我们在订阅的时候会明确的告诉事件,未来在你这个事件发生的时候,我将会通过哪个方法,来处理这个事件。
实例案件:Elapsed事件
首先,我们来看一下图片:
在time中可以看到一个类里最重要的三个成员:属性,方法和事件.
using UnityEngine;
using System.Timers;
using System;
//这个例子的功能:每隔N秒进行一个固定的行为功能(打印信息)
//事件的拥有者 => timer
//事件 => Elapsed
//事件的响应者 => Printer
//事件处理器 => 自定义的一个方法: Action, MyAction
//事件的订阅关系 => +=
public class EventEx : MonoBehaviour
{
Timer timer = new Timer();
public static int counter = 0;
public static string displayString = "This string will loop the Length.";//32长度
private void Start() {
//这里有2种解决方法:
//第一种是找到事件的那个约定,查找相关的参数
//第二种就是用VS直接快速构建
//简略格式
timer.Elapsed += Printer.MyAction;//Printer类事件处理器:MyAction订阅了由timer为主题的Elapsed事件
//完整格式
timer.Elapsed += new ElapsedEventHandler(Printer.MyAction);
timer.Interval = 500;//1000ms = 1s
timer.Start();
}
public class Printer {
internal static void MyAction(object sender, ElapsedEventArgs e) {
Debug.Log(counter++ % displayString.Length);
}
}
}
输出结果: