事件
场景需求:当某个特定的程序事件发生时,程序的其它部分可以得到该事件已经发生的通知。 发布者/订阅者模式可以满足该需求。
发布者/订阅者模式描述
- 发布者类定义一系列订阅者类感兴趣的事件。
- 订阅者类可以在事件上注册,以便这些事件发生时发布者可以通知它们。
- 注册是通过由订阅者类向发布者类提供一个方法来完成的。
- 当事件发生时,发布者触发事件,然后执行订阅者所提交的所有方法。
由订阅者提供的方法,称为回调方法,因为发布者通过执行这些方法来“往回调用订阅者的方法”,也可称为事件处理程序,因为它们是为处理事件而调用的代码。
发布者/订阅者的四大主体
发布者:发布事件的类或结构,其他类可以在事件发生时得到通知。
订阅者:注册并在事件发生时得到通知的类或结构。
事件处理程序(回调方法):由订阅者注册到事件上的方法,在事件触发时执行。可定义在不同的类和结构中。
触发事件:当事件触发时,所有在它上面注册的方法都会被依次执行。
事件和委托的关系
事件就像是用于某种特殊用途的委托。事件包含了一个私有委托。
事件提供了对其私有委托的结构化访问,类似于普通类中属性对字段的封装。
对于事件,我们只可以添加、删除和调用事件处理程序。
事件触发时,它通过委托来依次调用所有的事件处理程序。
事件五大组件
委托类型声明:事件和事件处理程序的签名和返回类型必须匹配,通过委托来描述。
事件实例
发布者类:
internal class TeaShop
{
private string shopName;
public TeaShop(string externShopNme)
{
this.shopName = externShopNme;
}
//声明事件
//事件在发布者类中声明(发布者类)
//事件基于委托来声明,因此需要知道委托类型的名字
//事件声明为public,这样其它类或结构才可以在它上面注册事件处理程序
//可在一条语句中声明多个事件,事件可以声明为静态的。
//事件和委托的区别
//事件不是一个类型,和方法、属性一样,事件是类或结构中的一个成员
//不可以在一段可执行代码中声明事件(函数内部)。
//事件声明必须在类或结构中,和其它成员一样。
//事件成员自动隐式初始化为null
//1.事件声明----新茶事件---基于委托定义
public event TeaDelegate NewTeaEvent;
//触发事件,写在发布者类
//事件本身只是保存了需要被调用的事件处理程序,如果事件没有被触发,什么都不会发生。我们需要
//在合适的时候有代码来做这件事情
//触发事件之前,将事件成员和null比较,从而确定事件上是否包含事件处理程序。
//触发事件的语法与调用方法一样,事件名(参数列表)
//新茶上市
//2.触发事件的代码
public void NewTeaCome(string teaName, float teaPrice)
{
Console.WriteLine("{0}:好消息好消息!新茶上市。品种:{1},价格:{2}",this.shopName,teaName,teaPrice);
//判断事件是否为空
if (NewTeaEvent != null)
{
NewTeaEvent(teaName, teaPrice);
}
}
}
订阅者类
internal class Consumer
{
private string name;
public Consumer(string externName)
{
this.name = externName;
}
/// <summary>
/// 订阅者类提供了事件处理程序
/// </summary>
/// <param name="teaName">茶名</param>
/// <param name="teaPrice">茶价</param>
//方法,消费者得到新茶的相关信息
//3.触发事件声明 与委托类型签名保持一致
public void GetNewTeaInfo(string teaName, float teaPrice)
{
Console.WriteLine("{0}:收到消息,新茶上市!品种:{1} 价格:{2}",this.name,teaName,teaPrice);
}
}
主程序类
//3.茶叶委托类型声明
public delegate void TeaDelegate(string teaName, float teaPrice);
internal class Program
{
static void Main(string[] args)
{
TeaEventTest();
Console.ReadLine();
}
//方法,茶事件测试
//订阅事件
//订阅者向事件上添加事件处理程序(注册)
//事件处理程序必须和事件的委托拥有相同的签名和返回值类型
//使用“+=”运算符来实现注册和订阅
static void TeaEventTest()
{
//创建发布者类
TeaShop teaShop = new TeaShop("东城茶叶专卖");
Consumer consumer = new Consumer("丁原");
Consumer consumer1 = new Consumer("叶修");
//4.注册事件、订阅事件
teaShop.NewTeaEvent += consumer.GetNewTeaInfo;
teaShop.NewTeaEvent += consumer1.GetNewTeaInfo;
//5.触发事件 新茶上市
teaShop.NewTeaCome("碧螺春", 200);
}
}