一、事件的五个组成部分
事件的定义:使对象或类具备通知能力的成员。
事件的使用场景:主要用于对象获类间的动作协调或消息传递。
C#中的事件概括来说有五个组成部分,分别是:
1、事件的拥有者(Event Source,对象)
2、事件(Event,成员)
3、事件的响应者(Event Subscribe,对象)
4、事件的处理器(Event Handler,成员)——本质上是一个回调方法
5、订阅关系(Event Handler——Event)把事件处理器和事件关联到一起,事件的响应者必须与声明事件时所用到的委托相匹配。
下面将对这五个部分分别展开介绍。
先举一个比较易懂的例子:微信公众号更新了文章,你收到推送然后打开阅读。
五个组成部分,公众号(EventSource),推文(Event)、你(EventSubscribe)、阅读(EventHandler),还有个隐含的就是你关注了这个微信公众号。
1、事件的拥有者 EventSource
事件的拥有者一定是一个对象或者说是一个类,事件是事件拥有者的一个字段成员。
例子:
//一个OfficialAccounts类
public class OfficialAccounts
{
public event OrderEventHandler ArticleUpdata;//事件成员
}
OfficialAccounts类就是事件的拥有者。
2、事件 Event
事件是一种可以使对象或类具备通知能力的成员。
如上述代码中的ArticleUpdata事件。
事件不会主动发生,只能被事件拥有者的内部逻辑所触发。
3、事件的响应者 Event Subscribe
订阅了事件的对象或者类,当事件发生的时候所有的事件响应者都会被依次通知到。
当公众号更新文章的时候,所有的订阅者都会收到更新的通知。
注:事件的响应者一定是一个对象或者说是一个类。
4、事件的处理器 Event Handler
事件响应者的一个方法成员。
开头的例子中的“阅读”就是微信使用者的一个方法,其他方法还有发送消息、发朋友圈等等。
5、订阅
主要处理三个问题:
1:事件发生的时候都有谁会被通知到,被通知到的对象一定是订阅了事件的对象。
2:拿什么样的方法或者说事件处理器才能处理事件。
比如你拿发朋友圈这个方法处理不了公众号更新这个事件(公众号更新了我不读,我发朋友圈,这肯定不能知道公众号更新的是什么内容。用当下流行的话来说:公众号更新了我不读,我就发朋友圈,哎,就是玩儿)
3、事件的响应者具体拿那个方法来处理事件。
至此事件的五个组成部分就介绍完了,下面就来结合具体的代码。结合代码可以再回头来看看这里的介绍会有更深的理解。
二、怎么写一个完整的事件
了解了事件的五个组成部分之后,再来结合具体的代码示例看一下怎么写一个完整的事件。
先来看代码。
我先定义了一个公众号类OfficialAccounts
public class OfficialAccounts
{
}
要声明一个事件必须先声明一个委托。注意这里委托要和类是一个级别的,委托也是一个类,当然也可以在类中声明类,但是这里我们先不用这种情景。
using System;
using System.Threading;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
Console.ReadLine();
}
}
public delegate void ArticleUpdataEventHandler();
public class OfficialAccounts
{
public event ArticleUpdataEventHandler ArticleUpdata;
}
}
声明了一个委托ArticleUpdataEventHandler,通过前面介绍我们知道委托其实是一种规则,用来规定事件的响应者要拿什么样的方法或者说事件处理器才能处理事件,我们这里的定义的委托的参数列表为空,参数列表就是这个委托所能引用的方法的参数列表,对于公众号的文章更新,我得要知道是哪个公众号,推送了什么文章,然后我打开这个公众号阅读这个文章,所以这里的委托的参数列表要有两个参数,第一个参数是哪个公众号,第二个参数是公众号更新的文章信息,公众号和文章,但是我们发现现在能包含文章信息的数据类型并不存在,所以要先声明这种数据类型,起名为ArticleUpdataEventArgs,并继承EventArgs,EventArgs是微软中委托参数的一个基类,修改后如下:
using System;
using System.Threading;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
Console.ReadLine();
}
}
public class ArticleUpdataEventArgs : EventArgs
{
public string Title { get; set; }
public string Content { get; set; }
}
public delegate void ArticleUpdataEventHandler(OfficialAccounts sender, ArticleUpdataEventArgs eventArgs);
public class OfficialAccounts
{
public event ArticleUpdataEventHandler ArticleUpdata;
}
}
然后我们再声明一个微信用户类:
public class WeChatUser
{
public void ReadAction(OfficialAccounts sender, ArticleUpdataEventArgs eventArgs)
{
Console.WriteLine("I Read this Article");
}
}
并给它写了一个可以用来响应事件的方法,这里注意方法的签名必须和委托一致,题外话,从这可以看出委托是一种规则,既能表明Event Source可以向外传递哪些信息,又能用来约束Event Subscribe使用什么样的签名来响应事件。
但是到目前为止还没有声明事件,所以接下来在OfficialAccounts类中声明文章更新事件,并定义一个文章更新后的处理方法OnPush()。
using System;
using System.Threading;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
Console.ReadLine();
}
}
public class ArticleUpdataEventArgs : EventArgs
{
public string Title { get; set; }
public string Content { get; set; }
}
public delegate void ArticleUpdataEventHandler(OfficialAccounts sender, ArticleUpdataEventArgs eventArgs);
public class OfficialAccounts
{
public event ArticleUpdataEventHandler ArticleUpdata;
public void UpdataArticle()
{
Console.WriteLine("I updated the article ");
OnPush();
}
public void OnPush()
{
if (this.ArticleUpdata != null)
{
ArticleUpdataEventArgs e = new ArticleUpdataEventArgs();
e.Content = "Unbelievable!!!!";
e.Content = "The man watched silence, the woman watched tears";
ArticleUpdata.Invoke(this, e);
}
}
}
public class WeChatUser
{
public void ReadAction(OfficialAccounts sender, ArticleUpdataEventArgs eventArgs)
{
Console.WriteLine("I Read this Article");
}
}
}
注意在OnPush中必须判断事件是否为null,因为事件为null表示没有被订阅,此时再Invoke会抛异常。
至此事件的五个组成部分中有四个组成部分都已经写好了,分别是:
1、事件拥有者:OfficialAccounts
2、事件:ArticleUpdata
3、事件响应者:WeChatUser
4、事件处理器:ReadAction
订阅还没有,接下来我们要在Main中建立订阅关系。
using System;
using System.Threading;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
OfficialAccounts officialAccounts = new OfficialAccounts();
WeChatUser weChatUser = new WeChatUser();
officialAccounts.ArticleUpdata += weChatUser.ReadAction ;
officialAccounts.UpdataArticle();
Console.ReadLine();
}
}
public class ArticleUpdataEventArgs : EventArgs
{
public string Title { get; set; }
public string Content { get; set; }
}
public delegate void ArticleUpdataEventHandler(OfficialAccounts sender, ArticleUpdataEventArgs eventArgs);
public class OfficialAccounts
{
public event ArticleUpdataEventHandler ArticleUpdata;
public void UpdataArticle()
{
Console.WriteLine("I updated the article ");
OnPush();
}
public void OnPush()
{
if (this.ArticleUpdata != null)
{
ArticleUpdataEventArgs e = new ArticleUpdataEventArgs();
e.Content = "Unbelievable!!!!";
e.Content = "The man watched silence, the woman watched tears";
ArticleUpdata.Invoke(this, e);
}
}
}
public class WeChatUser
{
public void ReadAction(OfficialAccounts sender, ArticleUpdataEventArgs eventArgs)
{
Console.WriteLine("I Read this Article");
}
}
}
至此,一个简单的完整的事件已经写完了。
三、事件和委托的关系
有人理解:事件就是一种以特殊方式声明的委托示例,其实这是不对的。
未完待续,后面再补充。。。。。