1.发布者和订阅者
很多程序都有一个共同的需求,即当一个特定的程序事件发生时,程序的其他部分可以得到该事件已经发生的通知
由订阅者提供的方法成为==回调方法==,因为发布者通过执行这些方法来“往回调用订阅者的方法”,还可以将它们称为==事件处理程序==。
1. 发布者类定义了==事件成员==
2. 订阅者注册在事件成员被触发时要调用的回调方法
3. 当发布者触发事件时,所有列表中的处理程序都会被调用
事件的很多部分都与委托类似,实际上,事件就像是专门用于某种特殊用途的简单委托。==事件包含了一个私有的委托==
- 事件中可用的操作比委托要少,对于事件我们只可以添加,删除或调用事件处理程序。
- 事件被触发时,它调用委托来依次调用调用列表中的方法。
2.声明事件
- 事件声明在一个类中
- 它需要委托类型的名称,任何附加到事件的处理程序都必须与委托类型的签名和返回类型匹配。
- 它声明为public,这样其他类和结构可以在它上面注册事件处理程序
- 不能使用对象创建表达式(new表达式)来创建它的对象
class Incrementer
{
public event EventHandler CountedDozen;
public event EventHandler MyEvent1,MyEvent2,MyEvent3;//声明一个以上的事件
public static event EventHandler CountedDozen;//声明静态事件
}
3.订阅事件
- 使用+=运算符来为事件增加处理程序
- 事件处理程序的规范可以是以下任意一种:
-
- 实例方法的名称
incrementer.CountedDozen+=IncrementDozensCount;
-
- 静态方法的名称
incrementer.CountedDozen+=ClassB.CounterHandlerB;
-
- 匿名方法
incrementer.CountedDozen+=delegate{DozensCount++};
-
- Lambda表达式
incrementer.CountedDozen+=()=>DozensCount++;
-
- 委托形式
mc.CountedDozen+=new EventHandler(cc.CounterHandler);
4.触发事件
delegate void Handler();//声明委托
class Incrementer//发布者
{
public event Handler CountedADozen;//创建事件并发布
public void DoCount()
{
for(int i=1;i<100;i++)
if(i%12==0&&CountedADozen!=null)
CountedADozen();//每增加12个计数触发事件一次
}
}
class Dozens//订阅者
{
public int DozensCount{get;private set;}
public Dozens(Incrementer incrementer)
{
DozensCount=0;
incrementer.CountedADozen+=IncrementDozensCount;//订阅事件
}
void IncrementDozensCount()//声明事件处理程序
{
DozensCount++;
}
}
class Program
{
static void Main()
{
Incrementer incrementer=new Incrementer();
Dozens dozensCounter=new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens={0}",dozensCounter.DozensCount);
}
}
5.标准事件的用法
对于事件的使用,.Net框架提供了一个标准模式。事件使用的标准模式的根本就是System命名空间声明的EventHandler委托类型
public delegate void EventHandler(object sender,EventArgs e);
- 第一个参数用来保存触发事件的对象的引用,由于是object类型的,所以可以匹配任何类型的实例;
- 第二个参数用来保存状态信息,指明什么类型适用于该应用程序;
- 返回类型是void
- EventArgs设计为不能传递任何数据,它用于不需要传递数据的事件处理程序——通常会被忽略
- 如果你希望传递数据,必须声明一个派生自EventArgs的类,使用合适的字段来保存需要传递的数据
class Incrementer//发布者
{
public event EventHandler CountedADozen;//使用系统定义的EventHandler委托
public void DoCount()
{
for(int i=1;i<100;i++)
if(i%12==0&&CountedADozen!=null)
CountedADozen(this,null);//触发事件时使用EventHandler的参数
}
}
class Dozens//订阅者
{
public int DozensCount{get;private set;}
public Dozens(Incrementer incrementer)
{
DozensCount=0;
incrementer.CountedADozen+=IncrementDozensCount;//订阅事件
}
void IncrementDozensCount(object source,EventArgs e)//事件处理程序的签名必须与委托的签名匹配
{
DozensCount++;
}
}
class Program
{
static void Main()
{
Incrementer incrementer=new Incrementer();
Dozens dozensCounter=new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens={0}",dozensCounter.DozensCount);
}
}
6.通过扩展EventArgs来传递数据
为了向自己的事件处理程序的第二个参数传入数据,并且又符合标准惯例,我们需要派生自EventArgs的自定义类,它可以保存我们需要传入的数据,类的名称应该以EventArgs结尾。例如,如下代码声明了一个自定义类,它能将字符串存储在名称为Message的字段中。
public class IncrementerEventArgs:EventArgs//自定义类派生自EventArgs
{
public int IterationCount{get;set;}//存储一个整数
}
class Incrementer//发布者
{
public event EventHandler<IncrementerEventArgs> CountedADozen;//使用自定义类的泛型委托
public void DoCount()
{
IncrementerEventArgs args=new IncrementerEventArgs();//自定义类对象
for(int i=1;i<100;i++)
if(i%12==0&&CountedADozen!=null)
CountedADozen(this,args);//在触发事件时传递参数
}
}
class Dozens//订阅者
{
public int DozensCount{get;private set;}
public Dozens(Incrementer incrementer)
{
DozensCount=0;
incrementer.CountedADozen+=IncrementDozensCount;//订阅事件
}
void IncrementDozensCount(object source,IncrmenterEventArgs e)//事件处理程序的签名必须与委托的签名匹配
{
DozensCount++;
}
}
class Program
{
static void Main()
{
Incrementer incrementer=new Incrementer();
Dozens dozensCounter=new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens={0}",dozensCounter.DozensCount);
}
}
移除事件处理程序用-=
7.事件访问器
+=和-=运算符是事件允许的唯一运算符,然而,我们可以修改这些运算符的行为,并且使用它们时可以让事件执行任何我们希望的自定义代码。要改变这两个运算符的操作,可以为事件定义事件访问器
- 有两个访问器:add和remove
- 声明事件访问器看上去跟声明一个属性差不多
public event EventHandler CountedADozen
{
add
{
...//执行+=运算符的代码
}
remove
{
...//执行-=运算符的代码
}
}
- 声明了事件访问器后,事件不包含任何内嵌委托对象,我们必须实现自己的机制来存储和移除事件注册的方法
- 事件访问器表现为void方法,也就是不能使用包含返回值的return语句。