事件的主要特点是一对多关联,即一个事件源,多个响应者。在具体技术上, .NET
Framework的事件处理机制是基于多路委托实现的。
8.1事件与多路委托
先看一个多路委托示例项目 MulticastDelegateLinkExample。
首先定义一个委托:
public delegate void MyMultiDelegate(int value );
接着,定义事件发布者与响应者类:
//事件发布者类
public class Publisher
{
public MyMultiDelegate handlers; //事件响应者清单
}
//事件响应者类
public class Subscriber
{
//事件处理函数
public void MyMethod(int i)
{
Console.WriteLine(i);
}
}
以下为模拟实现事件响应的代码:
static void Main(string[] args)
{
//一个事件源对象
Publisher p = new Publisher();
//两个事件响应者
Subscriber s1 = new Subscriber();
Subscriber s2 = new Subscriber();
//可以直接调用Delegate类的静态方法组合多个委托
p.handl ers = System.Delegate.Combine(p.handlers, new
MyMultiDelegate(s1.MyMethod)) as MyMultiDelegate;
p.handl ers = System.Delegate.Combine(p.handlers, new
MyMultiDelegate(s2.MyMethod)) as MyMultiDelegate;
//或调用+=运算符组合委托
//p.handlers += new MyMultiDelegate(s1.MyMethod);
//p.handlers += new MyMultiDelegate(s2.MyMethod);
//最简单的写法
//p.handlers += s1.MyMethod;
//p.handlers += s2.MyMethod;
//直接调用委托变量,代表激发事件
p.handlers(10);
}
上述代码执行到最后一句时,将会调用两个事件响应者 s1和 s2的事件响应函数
MyMethod,在控制台窗口输出两个整数:
10
10
上面这个例子中,事件的激发是在 Main()函数中引发的(即上述代码的最后一句),而
真实的事件不应允许由外界引发,必须由事件源对象自己引发。
为了限制事件的激发只能由事件源对象自己引发,C#引入了一个新的关键字——event,
为此需要修改 UseMultiDelegateExample项目(参看项目 UseEventExample):
public delegate void MyMultiDelegate(int value);
//事件发布者类
public class Publisher
{
public event MyMultiDelegate handlers; //定义一个事件
//激发事件
public void FireEvent()
{
handlers(10);
}
}
//事件响应者类
public class Subscriber
{
//事件处理函数
public void MyMethod(int i)
{
Console.WriteLine(i);
}
}
与前不同之处在于 Publisher类给 handlers字段增加了一个 event关键字,并提供了一个
新的用于激发事件的方法 FireEvent()。
以下为模拟实现事件响应的代码:
static void Main(string[] args)
{
Publisher p = new Publisher();
Subscriber s1 = new Subscriber();
Subscriber s2 = new Subscriber();
//声明为事件的委托无法直接调用Combine方法
//以下两句将无法通过编译
//p.handl ers = System.Delegate.Combine(p.handlers,
new MyMultiDelegate(s1.MyMethod)) as MyMultiDelegate;
//p.handl ers = System.Delegate.Combine(p.handlers,
new MyMultiDelegate(s2.MyMethod)) as MyMultiDelegate;
//必须使用+=运算符给事件追加委托
p.handlers+=new MyMultiDelegate(s1.MyMethod);
p.handlers+=new MyMultiDelegate(s2.MyMethod);
//声明为事件的委托也不能直接调用,下面这句无法通过编译
//p.handlers(10);
//只能通过类的公有方法间接地引发事件
p.FireEvent();
}
请注意上述代码中被注释掉的代码,它们是无法通过编译的,只能使用“+=”给 handles
事件追加委托,也只能通过类的公有方法来间接地激发此事件。
对比以上两个示例,不难看出事件与多路委托其实大同小异,只不过多路委托允许在
事件源对象之外激发事件罢了。
事件小结
面向对象的软件系统有许多都是事件驱动的,比如 ASP.NET就采用了“事件驱动”的
编程方式。
所谓“事件驱动”的开发方式,就是指整个系统包含许多的对象,这些对象可以引发多
种事件,软件工程师的主要开发工作就是针对特定的事件书写代码响应它们。
.NET事件处理机制建立在委托的基础之上,而这两者都是 ASP.NET技术的基础之一。
因此,必须牢固地掌握好委托和事件这两种编程技术,才能为掌握 ASP.NET技术扫清障碍。