前言
在应用开发中,我们经常会遇到当用户触发了某个事件后,需要处理这个事件对应的函数。
在这里我们引入了delegate 与 event来应对这种情况。
实现
举个例子
假如我要写一个看到人摔跤,就要上前将他扶起来并且确认有无大碍的程序。
public class Person { public Person(bool healthy, string name) { this.healthy = healthy; this.name = name; } public bool healthy { get; set; } public string name { get; set; } }
正常来讲可以这样实现:
Person p = new Person() { healthy = true,name = "小明"}; Console.WriteLine("{0}摔倒了",p.name); holdUp(p); isHealthy(p); static void holdUp(Person p) { Console.WriteLine("扶起了{0}", p.name); } static void isHealthy(Person p) { Console.WriteLine("健康:{0}", p.healthy); }
Output:
小明摔倒了
扶起了小明
健康:True
Delegate
但是引入了delegate委托后,我们可以通过
public class Handler { public delegate void PersonHandler(Person p); //这里C#我用了顶级语句,所以额外创建一个类存放委托 }
此处委托的定义类似于声明变量,但其实这是一种对类型的声明,可以在类中、直接在命名空间中、甚至是在全局命名空间中定义委托类型。于是在使用的时候,我们可以直接声明实例:
Handler.PersonHandler handler = new Handler.PersonHandler(holdUp); handler += isHealthy; Person p = new Person(true, "小明"); Console.WriteLine("{0}摔倒了", p.name); handler(p);
Output:
小明摔倒了
扶起了小明
健康:True
在这里,C#将方法附加到了委托上,通过一次触发,将附加到委托上的方法像放鞭炮一样按顺序点燃。
建议不要直接在全局命名空间中声明委托类型(或其他类型)。
Event
如果说delegate就是点鞭炮的打火机,那么event就是拿打火机的人,我们可以通过event来点火触发委托。
为Person类加入
public bool isFall { get; set; }
在Handler类中加入
public static event PersonHandler PersonEvent;
添加方法
public static void check(Person p) { Timer timer = new Timer(); timer.Elapsed += (o, s) => { /* * if(Tick){OnFall(Person p);} //触发事件 */ if (p.isFall) onFall(p); }; timer.Interval = 1000; timer.Start(); } private static void OnFall(Person p) { PersonEvent(p); }
该方法的作用是调用新线程,监听Person.isFall是否为真,若为真则触发OnFall()方法,再点燃event。
在程序入口中,我们要为event绑定委托,这样event才能知道要点燃哪些鞭炮。
Handler.PersonEvent += new Handler.PersonHandler(holdUp); Handler.PersonEvent += new Handler.PersonHandler(isHealthy); //绑定委托 Person p = new Person(true, "小明",false); Handler.check(p); p.isFall = true; //小明摔了 Console.WriteLine("{0}摔倒了", p.name); Thread.Sleep(1000); //主线程挂起休眠
Output:
小明摔倒了
扶起了小明
健康:True
总结
简单来说,一个简单的事件触发由发布-订阅[publisher-subscriber] 模型构成。
- 发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
- 订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。
在上述例子中,Handler类相当于发布器的角色,而holdUp与isHealthy应该是属于订阅器类的方法,通过这样一个简单的模型我们便可以完成监听+执行的行为。