14.1 发布者/订阅者
- 发布者(publisher):发布某个事件的类或结构,其他类可以在该事件发生时得到通知。
- 订阅者(subscriber):注册并在事件发生时得到通知的类或结构
- 事件处理程序(event handler) :由订阅者注册到事件的方法,在发布者触发事件时执行。事件处理程序方法可以定义在事件所在的类或结构中,也可以定义在不同的类或结构中。
- 触发(raise)事件 调用(invoke)或触发(fire)事件的术语:当事件触发时,所有注册到它的方法都会被依次调用。
有关事件的私有委托
- 事件提供了对它的私有控制委托的结构化访问。即你无法直接访问委托。
- 事件中可用的操作比委托少,对于事件我们只可以添加、删除或调用事件处理程序。
- 事件被触发时,它调用委托来依次调用调用列表中的方法。
14.2 源代码组件概览
一个完整的组件由5部分组成:
- 委托类型声明:事件和事件处理程序必须有共同的签名和返回类型,他们通过委托类型进行描述。
- 事件处理程序声明:订阅者类中会在事件触发时执行的方法声明。可以是显式命名的方法,也可以是匿名方法或Lambda表达式。
- 事件声明:发布者类必须声明一个订阅者类可以注册的事件成员。当声明的事件为public时,称为发布了事件。
- 事件注册:订阅者必须订阅事件才能在它被触发时得到通知。
-
触发事件的代码:发布者类中“触发”事件并导致调用注册的所有事件处理程序的代码。
使用事件时的5个源代码组件
static class Program
{
static void Main()
{
Incrementer incrementer = new Incrementer();
Dozens dozensCounter = new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
Console.ReadKey();
}
//发布者类
class Incrementer
{
public delegate void Handler();//委托类型声明
public event Handler CountADozen;//事件声明
public void DoCount()
{
for (int i = 1; i < 100; i++)
{
if (i % 12 == 0 && CountADozen != null)
{
CountADozen();//触发事件代码
}
}
}
}
//订阅者类
class Dozens
{
public int DozensCount { get; private set; }
public Dozens(Incrementer incrementer)
{
DozensCount = 0;
incrementer.CountADozen += IncrementerDozensCount;//事件注册
}
void IncrementerDozensCount()//事件处理程序声明
{
DozensCount++;
}
}
}
14.6 标准事件的用法
程序事件的异步处理是使用C#事件的绝佳场景。WindowsGUI编程广泛地使用了事件,.NET框架提供了一个标准模式。事件使用的标准模式的根本是System命名空间声明的EventHandler委托类型。
public delegate void EventHandler(object sender, EventArgs e);
- 第一个参数用来保存触发事件的对象的引用。由于是object类型,可以匹配任何类型的实例。
- 第二个参数用来保存状态信息,指明什么类型适用于该应用程序;
- 返回类型是 void
- EventArgs设计为不能传递任何数据。它用于不需要传递数据的事件处理程序——通常会被忽略。
- 如果要传递数据,必须声明一个派生自EventArgs的类,使用合适的字段来保存需要传递的数据。
修改上述程序使之使用标准EventHandler委托:
static class Program
{
static void Main()
{
Incrementer incrementer = new Incrementer();
Dozens dozensCounter = new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
Console.ReadKey();
}
class Incrementer
{
public event EventHandler CountADozen;//使用系统定义的EventHandler委托
public void DoCount()
{
for (int i = 1; i < 100; i++)
{
if (i % 12 == 0 && CountADozen != null)
{
CountADozen(this, null);//触发事件时使用EventHandler的参数
}
}
}
}
class Dozens
{
public int DozensCount { get; private set; }
public Dozens(Incrementer incrementer)
{
DozensCount = 0;
incrementer.CountADozen += IncrementerDozensCount;
}
void IncrementerDozensCount(object sender, EventArgs e)//事件处理程序的签名必须与委托的签名匹配
{
DozensCount++;
}
}
}
14.6.1 通过扩展EventArgs来传递参数
要向事件处理程序的第二个参数传入数据,需要声明一个派生自EventArgs的自定义类,可以保存要传的数据。
static class Program
{
static void Main()
{
Incrementer incrementer = new Incrementer();
Dozens dozensCounter = new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
Console.ReadKey();
}
public class IncrementerEventArgs : EventArgs//自定义类派生自EventArgs
{
public int IterationCount { get; set; }//存储一个整数
}
class Incrementer
{
public event EventHandler<IncrementerEventArgs> CountADozen;//使用、自定义类的泛型委托
public void DoCount()
{
IncrementerEventArgs args = new IncrementerEventArgs();//自定义类对象
for (int i = 1; i < 100; i++)
{
if (i % 12 == 0 && CountADozen != null)
{
CountADozen(this, args);//触发事件时传递参数
}
}
}
}
class Dozens
{
public int DozensCount { get; private set; }
public Dozens(Incrementer incrementer)
{
DozensCount = 0;
incrementer.CountADozen += IncrementerDozensCount;
}
void IncrementerDozensCount(object sender, IncrementerEventArgs e)//事件处理程序的签名必须与委托的签名匹配
{
Console.WriteLine("Incremented at iteration: {0} in {1}", e.IterationCount, sender.ToString());
DozensCount++;
}
}
}
网友评论