C#事件
发布者和订阅者
在开发中会有一个共同的需求,即当一个特定的程序事件发生时,程序的其他部分可以得到该事件已发生的通知。
发布者/订阅者模式可以满足这种需求。在这种模式中,发布者类定义了一系列程序的事件,其他程序可以注册,注册之后就可在事件触发时接到通知。
- 发布者
发布某个事件的类或结构,其他类可以在该事件发生时得到通知。 - 订阅者
注册并在事件发生时得到通知的类或结构。 - 事件处理程序
由订阅者注册到事件的方法,在发布者触发事件时执行。事件处理程序方法可以定义在事件所在的类或结构中,也可以定义在不同的类或结构中。
声明事件
发布者类必须提供事件对象。创建事件比较简单——只需要委托类型和名字。事件声明的语法如下代码所示,代码中声明了一个叫做CountADozen的事件。注意如下有关CountedADozen事件的内容。
- 事件声明在一个类中。
- 它需要委托类型的名称,任何附加到事件(如注册)的处理程序都必须与委托类型的签名和返回类型匹配。
- 它声明为public,这样其他类和结构可以在它上面注册事件处理程序。
- 不能使用对象创建表达式(new表达式)来创建它的对象。
class Incrementer
{ 关键字 事件名
↓ ↓
public event EventHandler CountedADozen;
↑
委托类型
}
订阅事件
订阅者向事件添加事件处理程序。对于一个要添加到事件的事件处理程序来说,它必须具有与事件的委托相同的返回类型和签名。
- 使用+=运算符来为事件增加事件处理程序,如下面代码所示。事件处理程序位于该运算符的右边。
- 事件处理程序的规范可以是以下任意一种:
- 实例方法的名称;
- 静态方法的名称
- 匿名方法;
- Lambda表达式
例如,下面代码为CountedADozen事件增加了3个方法:第一个是使用方法形式的实例方法,第二个是使用方法形式的静态方法,第三个是使用委托形式的实例方法。
类 实例方法
↓ ↓
incrementer.CountedADozen += IncrementDozensCount; //方法引用形式
incrementer.CountedADozen += ClassB.CounterHandlerB; //方法引用形式
↑ -----------↑-----------
事件成员 静态方法
mc.CountedADozen += new EventHandler(cc.CounterHandlerC); //委托形式
// Lambda表达式
incrementer.CountedADozen += () => DozensCount++;
// 匿名方法
incrementer.CountedADozen += delegate { DozensCount++; };
触发事件
事件成员本身只是保存了需要被调用的事件处理程序。如果事件没有被触发,什么都不会发生。我们需要确保在合适的时候有代码来做这件事情。
例如,如下代码触发了CountedADozen事件。注意如下有关代码的事项。
if (CountedADozen != null) //确认有方法可以执行
CountedADozen (source, args); //触发事件
↑ -----↑------
事件名 参数列表
把事件声明和触发事件的代码放在一起便有了如下的发布者类声明。这段代码包含了两个成员:事件和一个叫做DoCount的方法,它将在适当的时候触发该事件。
class Incrementer{
public event EventHandler CountedADozen; //声明事件
void DoCount(object source, EventArgs args)
{
for( int i=1; i < 100; i++ )
if( i % 12 == 0 )
if (CountedADozen != null) //确认有方法可以执行
CountedADozen(source, args);
} ----------↑-----------------
触发事件}