首先, 我们需要知道, 到底在什么情况下必须使用委托和事件呢?
请看下面的场景: 首领 A 要搞一场鸿门宴, 吩咐部下 B 和 C 各自带队埋伏在屏风两侧, 约定以杯为令: 若左手举杯, 则 B 带队杀出; 若右手举杯, 则 C 带队杀出; 若直接摔杯, 则 B 和 C 同时杀出. B 和 C 袭击的具体方法, 首领 A 并不关心.(完整代码在全文最后.)
有脑子反应快的同学, 马上说, 这个逻辑, 用一个 IF 条件判断语句不就搞定了吗:
- if(左手举杯)
- {
B 带队杀出;
- }
- else if(右手举杯)
- {
C 带队杀出;
- }
- else if(直接摔杯)
- {
B 带队杀出;
C 带队杀出;
}
else
{
按兵不动
}
如果真这么简单, 那我还写这篇文章干嘛呢. 请这位同学认真想想: 首领 A 会什么时候发出信号呢? 估计连他自己都不知道. 那么上面这段伪码, 你打算插入到哪里呢? 难道 B 和 C 就一直不停的用 While 循环做上述判断吗? 显然不合适吧. 更重要的, 如果扩展一下, 部下不止 B 和 C, 而是 B,C,D,E 等等, 每个人都有自己不同的响应领导号召的方法, 那么对首领 A 而言, 要分别去跟每个部下打交道, 上述的伪码, 会进行无尽的扩展和完善, 显然也不是我们所希望的.
正确的逻辑应该是, B 和 C 不管宴席上发生的任何其他事情, 只等首领发出举杯或者摔杯的信号, 一旦首领 A 发出信号, 相当于通知了所有部下, 凡是约定好的部下, 都立马各自行动!
我们定义三个类, 分别模拟首领 A 和部下 B,C:
- /// <summary>
- /// 首领 A
- /// </summary>
- public class A
- {
- }
- /// <summary>
- /// 部下 B
- /// </summary>
- public class B
- {
- }
- /// <summary>
- /// 部下 C
- /// </summary>
- public class C
- {
- }
首领 A 的类有举杯和摔杯两种方法, 其中, 举杯方法带有一个形参, 用于传递是左手举杯, 还是右手举杯. 部下 B 和 C 的类, 各自有一种攻击方法.
- /// <summary>
- /// 首领 A
- /// </summary>
- public class A
- {
- /// <summary>
- /// 举杯
- /// </summary>
- /// <param name="hand"> 手: 左, 右 </param>
- public void Raise(string hand)
- {
- Console.WriteLine("首领 A{0} 手举杯", hand);
- }
- /// <summary>
- /// 摔杯
- /// </summary>
- public void Fall()
- {
- Console.WriteLine("首领 A 摔杯");
- }
- }
- /// <summary>
- /// 部下 B
- /// </summary>
- public class B
- {
- /// <summary>
- /// 攻击
- /// </summary>
- public void Attack()
- {
- Console.WriteLine("部下 B 发起攻击");
- }
- }
- /// <summary>
- /// 部下 C
- /// </summary>
- public class C
- {
- /// <summary>
- /// 攻击
- /// </summary>
- public void Attack()
- {
- Console.WriteLine("部下 C 发起攻击");
- }
- }
至此, 三个独立的类, 构造完毕. 那么, 怎么让部下 B 和 C, 根据首领的暗语才去相应的行动呢?
我们需要在首领 A 类中, 采用一种方法, 把其意图传递出去. 在首领 A 类之前, 分别定义一个带形参的举杯委托 RaiseEventHandler 和一个不带形参的摔杯委托 FallEventHandler. 命名规则是在准备传递的方法名后加上 EventHandler, 不要问我为什么, 介绍为什么的文章多得是, 大家大可以去查阅. 本文的宗旨是, 教会大家如何快速的使用委托和事件. 当然, 你也可以不遵循此命名规则, 对程序的运行没有任何影响, 只是会增加自己或他人日后阅读代码的难度.
- delegate void RaiseEventHandler(string hand);
- delegate void FallEventHandler();
然后, 在首领 A 类中, 定义两个事件. 这个类似于大家在 WinForm 中拖放一个 Button 后, 双击该 Button, 即可编辑其事件.
- /// <summary>
- /// 首领 A 举杯事件
- /// </summary>
- public event RaiseEventHandler RaiseEvent;
- /// <summary>
- /// 首领 A 摔杯事件
- /// </summary>
- public event FallEventHandler FallEvent;
好了, 做完上面两个步骤后, 就可以在首领 A 的举杯和摔杯方法中, 调用上述两个事件了. 这样, 如果 B 和 C 中订阅该事件, 便可自动执行了.
- /// <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();
- }
- }
同样, 不要问为什么这样写. 按照上述操作即可. 一旦用熟这种方法, 体会其中含义, 自然就明白为何这么写了.
在部下 B 和 C 心中, 必须存在首领 A, 才能执行 A 的暗示吧. 所以, 在 B 类和 C 类中, 需要声明一个 A, 该声明可以通过 B 和 C 的构造函数进行实例化. 实例化之后, 便可在类 B 和类 C 中订阅类 A 的事件了.
完整代码如下:
- 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 均会按照约定进行动作.
- }
- }
- /// <summary>
- /// 首领 A 举杯委托
- /// </summary>
- /// <param name="hand"> 手: 左, 右 </param>
- public delegate void RaiseEventHandler(string hand);
- /// <summary>
- /// 首领 A 摔杯委托
- /// </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();
- }
- }
- }
- /// <summary>
- /// 部下 B
- /// </summary>
- 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 发起攻击, 大喊: 猛人张飞来也!");
- }
- }
- /// <summary>
- /// 部下 C
- /// </summary>
- 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 发起攻击, 一套落英神掌打得虎虎生威~");
- }
- }
来源: http://www.bubuko.com/infodetail-3716490.html