C# event 事件
事件第二篇:https://www.cnblogs.com/FavoriteMango/p/11731485.html
曾经面试碰到一道设计题:
现有一个人,一群鸟,人有一把手枪,当人开枪时,所有的鸟都被吓飞了。要求按照题干设计程序且有一定的扩展性。
当时我并无任何的程序设计知识,看到该题一点解决办法也没有,按照面向过程完全可以写流程出来,但“光写流程”并不符合C#面向对象的的思想,写出来也不具有任何扩展性。
直到后来学习了事件的相关知识,可能目前仍然不清楚如何扩展,但至少可以写个像模像样的程序出来。
1.事件的组成
事件的组成分为5个部分:
(1)事件的拥有者
(2)事件本身
(3)事件的订阅者
(4)事件处理器
(5)订阅事件
事件的拥有者,或者说这件事的发起者,以上题为例,人开枪,人便是发起事件的对象,是事件的拥有者;事件的本身,开枪这件事便是事情的本身;事件的订阅者,也就是关注事件发生的对象,题中开枪后鸟都飞走了,鸟是听到枪响才飞走的,也就是说鸟是关注“开枪”这件事的对象;事件处理器,订阅者在关注到事件发生后,针对事件作出的反应。鸟在枪响后都被吓得飞走了,“飞走”便是它们针对“开枪”作出的事件处理。此外,事件的发生和事件处理都是一种动作,两者紧密相连却又互不相同,在处理事件的逻辑时一定要分清二者的界限,切不可混为一谈而导致逻辑混乱;而订阅事件,这实际是一种关系,这个关系是联系拥有者和订阅者、事件和事件处理的一个“纽带”。就好比你家里做好了饭,家里人通知你饭做好了,你知道要开饭了于是赶紧回家,因为你是“关注”家里“开饭”这件事的,这便是订阅事件。
2.事件的使用
定义事件的关键字是event,并且事件定义时需要搭配委托,语法:修饰符 + event + 委托类型 + 名称。
事件的触发只能在被声明该事件的类中进行,语法与类方法调用相同,所以事件是不能直接在类体之外触发的,若想在程序的其他地方触发方法,必须要用类方法在类体中封装事件。
事件的订阅需要用到“+=”操作符,语法:实体类名称.事件 += 方法(事件处理器)。由于事件依托委托来声明,所以一个事件可以挂接多个事件处理器,也就是说可以被多个对象订阅。
回到题目,理清楚题目中的对象分别对应组成事件的哪个部分,人是事件的发起者、开枪是事件本身,鸟是事件的订阅者,它订阅了开枪这件事,而飞走是它对开枪这件事的处理。写成代码大概是下面这个样子:
//人
public class Man
{
//人的事件(这里用了执行无参数无返回值方法的委托类型)
public event Action Fire;
//封装了事件的类方法
public void Action()
{
if (Fire != null)
{
Console.WriteLine("人开枪了");
//触发事件
Fire();
}
}
}
//鸟
public class Bird
{
public string birdName { get; set; }
//声明一个集合类型的静态字段,用于保存实例化的所有Bird类
public static List<Bird> Birds = new List<Bird>();
//这是鸟类对于开枪的事件处理器
internal static void Fly()
{
for (int i = 0; i < Birds.Count; i++)
{
Console.WriteLine(Birds[i].birdName + "飞走了");
}
}
//每一次实例化都会在构造函数中保存当前实例化的Bird类
public Bird()
{
Birds.Add(this);
}
}
class Program
{
static void Main(string[] args)
{
//实例化对象
Man man = new Man();
//订阅事件,联结两类对象中的事件和事件处理器
man.Fire += Bird.Fly;
//循环生成Bird类
for (int i = 0; i < 5; i++)
{
Bird bird = new Bird();
bird.birdName = "小鸟" + i;
}
//调用封装事件的方法,触发事件
man.Action();
}
}