如果类型定义了事件成员,那么类型(或类型实例)就可以通知其他对象发生了特定的事情。例如Button类提供了一个名为Click的事件,应用程序中的一个或多个对象可能想接收关于这个事件的通知,以便在Button被点击之后采取某些操作。事件是实现这种交互的类型成员。具体的说,如果定义一个事件成员,意味着类型要提供以下能力:
1. 方法可登记它对该事件的关注;
2. 方法可注销它对该事件的关注;
3. 该事件发生时,登记了的方法会受到通知。
和观察者模式非常类似。。。
类型之所以能提供事件的通知功能,是因为类型维护了一个已登记方法的列表,事件发生后,类型将通知列表中所有已登记的方法。
事件创建代码示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace CreateEvent
{
// NO.1 定义一个类型 作用:容纳 所有 需要发送给 事件 通知 接收者 的附加信息
internal class NewMailEventArgs: EventArgs
{
private readonly string m_From, m_To, m_Subject;
public NewMailEventArgs(string From, string To, string Subject)
{
m_From = From;
m_To = To;
m_Subject = Subject;
}
public string From { get { return m_From; } }
public string To { get { return m_To; } }
public string Subject { get { return m_Subject; } }
}
/// <summary>
/// 扩展方法的应用(this 关键字)
/// </summary>
public static class EventArgExtensions
{
// where关键字用于约束:TEventArgs 必须是 EventArgs 类型的
public static void Raise<TEventArgs>(this TEventArgs e, object sender,
ref EventHandler<TEventArgs> eventDelegate)
where TEventArgs : EventArgs
{
// 出于线程安全的考虑,现在将对委托字段的引用复制到一个临时字段中
EventHandler<TEventArgs> temp = Interlocked.CompareExchange(ref eventDelegate, null, null);
// 任何方法登记了对事件的关注,就通知他们
if (temp != null)
{
temp(sender, e);
}
}
}
/// <summary>
/// 包含 事件的 类
/// </summary>
internal class MailManager
{
// NO.2 定义事件成员
public event EventHandler<NewMailEventArgs> NewMail;
// NO.3 定义一个负责引发事件的方法,它通知已登记的对象 事件已经发生。
// 如果类是密封的,这个方法要声明为私有和非虚
protected virtual void OnNewMail(NewMailEventArgs e)
{
// 调用扩展方法(Raise是一个静态方法,但e是一个实例)
e.Raise(this, ref NewMail);
}
// No.4 定义一个方法,将输入转化为期望事件
public void SimulateNewMail(string From, string To, string Subject)
{
// 构造一个对象来容纳 想传给通知接收者的信息
NewMailEventArgs e = new NewMailEventArgs(From, To, Subject);
// 调用虚方法通知对象 事件已发生,如果没有重写虚方法,该对象将通知事件的所有登记对象
OnNewMail(e);
}
}
}
事件发生时,被通知的类型:
internal sealed class Fax
{
/// <summary>
/// 将MailManage对象传给构造器
/// </summary>
/// <param name="mm"></param>
public Fax(MailManager mm)
{
// 构造 EventHandler<NewMailEventArgs> 委托的一个实例,
// 使它引用我们的FaxMsg回调方法。
// 向 MailManage 的NewMail事件 登记我们的回调方法
// 类似观察者模式(观察者向被观察者注册)
mm.NewMail += FaxMsg;
}
/// <summary>
/// 向MailManage对象的NewMail事件 注销自己对它的关注
/// </summary>
/// <param name="mm"></param>
public void Unregister(MailManager mm)
{
mm.NewMail -= FaxMsg;
}
/// <summary>
/// 新电子邮件到达时,MailManage将调用这个方法
/// </summary>
/// <param name="sender">表示MailManage对象,便于将信息传给它</param>
/// <param name="e">表示MailManage对象想传给我们的附加事件信息</param>
private void FaxMsg(object sender, NewMailEventArgs e)
{
System.Windows.Forms.MessageBox.Show("Fax Mail message:From:" + e.From + "," +
"To:" + e.To + "," +
"Subject:" + e.Subject);
}
}
测试代码:
private void button1_Click(object sender, EventArgs e)
{
// mm:被观察者
MailManager mm = new MailManager();
// pFax,pPhone,pPlayer:观察者
Fax pFax = new Fax(mm);
// 触发事件
mm.SimulateNewMail("大花", "小花", "Happy New Year!");
// 取消关注
pFax.Unregister(mm);
pFax = null;
mm = null;
}
代码执行效果:弹出提示框 “Fax Mail message:From:大花,To:小花,Subject:Happy New Year!”。