C#中的委托和事件学习(续)

2019-05-12 07:23:05王冬梅

class Program6 {
   static void Main(string[] args) {

     Publisher pub = new Publisher();
     Subscriber1 sub1 = new Subscriber1();
     Subscriber2 sub2 = new Subscriber2();
     Subscriber3 sub3 = new Subscriber3();

     pub.MyEvent += new EventHandler(sub1.OnEvent);
     pub.MyEvent += new EventHandler(sub2.OnEvent);
     pub.MyEvent += new EventHandler(sub3.OnEvent);

     pub.DoSomething();   // 触发事件

    Console.WriteLine("nControl back to client!"); // 返回控制权
  }

   // 触发某个事件,以列表形式返回所有方法的返回值
  public static object[] FireEvent(Delegate del, params object[] args) {
     // 代码与上同,略
  }
 }

public class Publisher {
   public event EventHandler MyEvent;
   public void DoSomething() {
     // 做某些其他的事情
    Console.WriteLine("DoSomething invoked!");
     Program6.FireEvent(MyEvent, this, EventArgs.Empty); //触发事件
  }
 }

public class Subscriber1 {
   public void OnEvent(object sender, EventArgs e) {
     Thread.Sleep(TimeSpan.FromSeconds(3));
     Console.WriteLine("Waited for 3 seconds, subscriber1 invoked!");
   }
 }
public class Subscriber2 {
   public void OnEvent(object sender, EventArgs e) {
     Console.WriteLine("Subscriber2 immediately Invoked!");
   }
 }
public class Subscriber3 {
   public void OnEvent(object sender, EventArgs e) {
     Thread.Sleep(TimeSpan.FromSeconds(2));
     Console.WriteLine("Waited for 2 seconds, subscriber2 invoked!");
   }
 }

在这段代码中,我们使用Thread.Sleep()静态方法模拟了方法超时的情况。其中Subscriber1.OnEvent()需要三秒钟完成,Subscriber2.OnEvent()立即执行,Subscriber3.OnEvent需要两秒完成。这段代码完全可以正常输出,也没有异常抛出(如果有,也仅仅是该订阅者被忽略掉),下面是输出的情况:


DoSomething invoked!
Waited for 3 seconds, subscriber1 invoked!
Subscriber2 immediately Invoked!
Waited for 2 seconds, subscriber2 invoked!

Control back to client!

但是这段程序在调用方法DoSomething()、打印了“DoSomething invoked”之后,触发了事件,随后必须等订阅者的三个方法全部执行完毕了之后,也就是大概5秒钟的时间,才能继续执行下面的语句,也就是打印“Control back to client”。而我们前面说过,很多情况下,尤其是远程调用的时候(比如说在Remoting中),发布者和订阅者应该是完全的松耦合,发布者不关心谁订阅了它、不关心订阅者的方法有什么返回值、不关心订阅者会不会抛出异常,当然也不关心订阅者需要多长时间才能完成订阅的方法,它只要在事件发生的那一瞬间告知订阅者事件已经发生并将相关参数传给订阅者就可以了。然后它就应该继续执行它后面的动作,在本例中就是打印“Control back to client!”。而订阅者不管失败或是超时都不应该影响到发布者,但在上面的例子中,发布者却不得不等待订阅者的方法执行完毕才能继续运行。