委托事件
1.概念
委托:一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。你可以通过委托实例调用方法。委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。
事件:类或对象可以通过事件向其他类或对象通知发生的相关事情。发送(或引发)事件的类称为“发布者”,接收(或处理)事件的类称为“订阅者”。
2.示例
2.1水壶烧水事件
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace task3 { public delegate void MyAlarm(int temperature); //创建委托报警 public delegate void MyDispaly(int temperature); //创建委托显示 class Heater //热水器类 { private int temperature; //温度 public int Temperature { get { return temperature; } set { if ((temperature >= 0) && (temperature <= 100)) temperature = value; else Console.WriteLine("温度有问题!显示出错!"); } } public event MyAlarm DoMyAlarm; //建立事件报警 public event MyDispaly DoMyDisplay; //建立事件显示 public void BoilWater(int m) //m 表示烧水时间,没分钟提高摄氏度 { Console.WriteLine("感谢您使用热水器,现在温度为{0},\n本次烧水时间为{1}分钟。" + "(每分钟提高10摄氏度)", this.temperature, m); this.temperature = m * 10 + this.temperature; if (this.temperature >= 100) this.temperature = 100; if (this.temperature >= 95) { DoMyAlarm(this.temperature); DoMyDisplay(this.temperature); Console.WriteLine(""); } else Console.WriteLine("目前还没烧开!\n"); } } class Alarm //报警器类 { public void MakeAlert(int temperature) { Console.WriteLine("叮叮叮,叮叮叮。。。\n报警器提示水壶水温现在是{0}",temperature); } } class Display //显示器类 { public void ShowMsg(int temperature) { Console.WriteLine("显示器提示现在的水温为{0}", temperature); } } class Program { static void Main(string[] args) { Heater he1 = new Heater(); //第一次烧水(水伟烧开,不会触发事件) he1.Temperature = 10; Alarm al1 = new Alarm(); Display di1 = new Display(); he1.DoMyAlarm += al1.MakeAlert; //建立关联 he1.DoMyDisplay += di1.ShowMsg; //建立关联 he1.BoilWater(1); Heater he2 = new Heater(); //第二次烧水(水烧开,触发显示与报警事件) he2.Temperature = 10; Alarm al2 = new Alarm(); Display di2 = new Display(); he2.DoMyAlarm += al2.MakeAlert; //建立关联 he2.DoMyDisplay += di2.ShowMsg; //建立关联 he2.BoilWater(10); Console.Read(); } } }
2.2 情景二
首领A要搞一场鸿门宴,吩咐部下B和C各自带队埋伏在屏风两侧,约定以杯为令:若左手举杯,则B带队杀出;若右手举杯,则C带队杀出;若直接摔杯,则B和C同时杀出。B和C袭击的具体方法,首领A并不关心;
首领A类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo { /// <summary> /// 首领举杯委托 /// </summary> /// <param name="hand">手:左,右</param> public delegate void RaiseEventHandler(string hand); /// <summary> /// 首领摔杯委托 /// </summary> public delegate void FallEventHandler(); /// <summary> /// 首领A /// </summary> public class A { /// <summary> /// 首领A举杯事件 /// </summary> public event RaiseEventHandler RaiseEvent; /// <summary> /// 首领A摔杯事件 /// </summary> public event FallEventHandler FallEvent; /// <summary> /// 举杯 /// </summary> /// <param name="hand">手:左、右</param> public void Raise(string hand) { Console.WriteLine("首领A{0}手举杯", hand); // 调用举杯事件,传入左或右手作为参数 if (RaiseEvent != null) { RaiseEvent(hand); } }
/// <summary> /// 摔杯 /// </summary> public void Fall() { Console.WriteLine("首领A摔杯"); // 调用摔杯事件 if (FallEvent != null) { FallEvent(); } } } }
首领A的类有举杯和摔杯两种方法,其中,举杯方法带有一个形参,用于传递是左手举杯,还是右手举杯。部下B和C的类,各自有一种攻击方法。
部下B类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo { public class B { A a; public B(A a) { this.a = a; a.RaiseEvent += new RaiseEventHandler(a_RaiseEvent); // 订阅举杯事件 a.FallEvent += new FallEventHandler(a_FallEvent); // 订阅摔杯事件 } /// <summary> /// 首领举杯时的动作 /// </summary> /// <param name="hand">若首领A左手举杯,则B攻击</param> void a_RaiseEvent(string hand) { if (hand.Equals("左")) { Attack(); } } /// <summary> /// 首领摔杯时的动作 /// </summary> void a_FallEvent() { Attack(); } /// <summary> /// 攻击 /// </summary> public void Attack() { Console.WriteLine("部下B发起攻击,大喊:猛人张飞来也!"); } } }
部下C类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace demo { public class C { A a; public C(A a) { this.a = a; a.RaiseEvent += new RaiseEventHandler(a_RaiseEvent); // 订阅举杯事件 a.FallEvent += new FallEventHandler(a_FallEvent); // 订阅摔杯事件 } /// <summary> /// 首领举杯时的动作 /// </summary> /// <param name="hand">若首领A右手举杯,则攻击</param> void a_RaiseEvent(string hand) { if (hand.Equals("右")) { Attack(); } } /// <summary> /// 首领摔杯时的动作 /// </summary> void a_FallEvent() { Attack(); } /// <summary> /// 攻击 /// </summary> public void Attack() { Console.WriteLine("部下C发起攻击,一套落英神掌打得虎虎生威~"); } } }
我们需要在首领A类中,采用一种方法,把其意图传递出去。在首领A类之前,分别定义一个带形参的举杯委托RaiseEventHandler和一个不带形参的摔杯委托FallEventHandler。
在部下B和C心中,必须存在首领A,才能执行A的暗示吧。所以,在B类和C类中,需要声明一个A,该声明可以通过B和C的构造函数进行实例化。实例化之后,便可在类B和类C中订阅类A的事件了。
using System; namespace demo { class Program { static void Main(string[] args) { A a = new A(); // 定义首领A B b = new B(a); // 定义部下B C c = new C(a); // 定义部下C // 首领A左手举杯 a.Raise("左"); // 首领A右手举杯 //a.Raise("右"); // 首领A摔杯 //a.Fall(); Console.ReadLine(); // 由于B和C订阅了A的事件,所以无需任何代码,B和C均会按照约定进行动作。 } } }