订阅者方法超时会让客户端程序出现某种程度的中断。
模拟考试,比较现实的状况是谁先答完,谁先交试卷,不可能按学生序号来决定交试卷顺序。
先模拟一个订阅者方法超时
□ 老师的职责是组织考试,并让每个注册学生(订阅者)答题。
1: public class Teacher
2: {
3: public event EventHandler TestEvent;
4:
5: public void Test()
6: {
7: Console.WriteLine("老师:同学们,现在开始考试");
8:
9: //触发事件的所有注册方法
10: //实际上也有返回值的,只不过没有获取
11: //第二个参数是被监视对象,相当于object sender
12: EventHelper.FireEvent(TestEvent, this, EventArgs.Empty);
13: }
14: }
□ EventHelper是关于触发注册方法的静态类。主要是遍历委托链表,让链表上的每个方法得以执行
□ 学生的职责是考试,答题速度有快有慢
1: public class Student1
2: {
3: public void DoTest(Object sender, EventArgs e)
4: {
5: Thread.Sleep(TimeSpan.FromSeconds(3));
6: Console.WriteLine("Student1用了3秒钟答题交试卷了");
7: }
8: }
9:
10: public class Student2
11: {
12: public void DoTest(Object sender, EventArgs e)
13: {
14: Thread.Sleep(TimeSpan.FromSeconds(2));
15: Console.WriteLine("Student2用了2秒钟答题交试卷了");
16: }
17: }
18:
19: public class Student3
20: {
21: public void DoTest(Object sender, EventArgs e)
22: {
23: Thread.Sleep(TimeSpan.FromSeconds(1));
24: Console.WriteLine("Student3用了1秒钟答题交试卷了");
25: }
26: }
□ 主程序注册方法,老师触发宣布考试开始
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: Teacher teacher = new Teacher();
6: Student1 student1 = new Student1();
7: Student2 student2 = new Student2();
8: Student3 student3 = new Student3();
9:
10: teacher.TestEvent += new EventHandler(student1.DoTest);
11: teacher.TestEvent += new EventHandler(student2.DoTest);
12: teacher.TestEvent += new EventHandler(student3.DoTest);
13:
14:
15: teacher.Test();
16: Console.WriteLine("老师:考试结束");
17: Console.ReadKey();
18: }
19: }
□ 结果
□ 可见
不管学生的答题速度如何,都是按学生编号顺序交试卷,显然不合理。
使用EventHandler的BeginInvoke()方式实现异步执行订阅者方法
修改老师的类,让老师用异步方法来触发订阅者方法。
1: public class Teacher
2: {
3: public event EventHandler TestEvent;
4:
5: public void Test()
6: {
7: Console.WriteLine("老师:同学们,现在开始考试");
8:
9: if (TestEvent != null)
10: {
11: Delegate[] delArray = TestEvent.GetInvocationList(); //获取事件的委托链表
12: foreach (Delegate del in delArray)
13: {
14: EventHandler method = (EventHandler)del;
15: method.BeginInvoke(null, EventArgs.Empty, null, null);
16: }
17: }
18: }
19: }
可见:
● 当异步执行订阅者方法的时候,客户端程序不会等到所有订阅者方法执行完成才进行,而是不理会订阅者的异步方法执行结果。
● 当异步执行订阅者方法的时候,最先执行完的先返回结果。
● BeginInvoke()是事件的方法,不是Delegate的方法,只能把委托链表中的委托向下转换成事件,再让事件执行异步方法。