C#委托和事件学习

  周末闲暇随时拿了一本比较老的Windows Forms教材书《Windows Forms程序设计》看到附录里有用具体事例讲解C#的委托和事件,看了感觉不错,按照作者的思路,再整理一遍,感觉比较好的就是通过实际使用的场景,再一步一步的推进使用委托、事件。

  不多说,上代码。  

View Code
 1 ///<summary>
2 /// 最原始的,通过方法的形式通知消息
3 ///</summary>
4 class Worker
5 {
6 Boss boss;
7 ///<summary>
8 /// 提供方法以传入Boss对象
9 ///</summary>
10 ///<param name="boss"></param>
11 public void Advise(Boss boss) { this.boss = boss; }
12
13 ///<summary>
14 /// Worker开工
15 ///</summary>
16 public void DoWork()
17 {
18 //通知Boss,Worker开工了
19 Console.WriteLine("Worker:work started,notice boss");
20 if (boss != null)
21 {
22 boss.WorkStarted();
23 }
24
25
26 Console.WriteLine("Worker:work progressing,notice boss");
27 if (boss != null) boss.WorkProgressing();
28
29 //通知Boss,Workerr做完了,等你打分
30 Console.WriteLine("Worker:work complete,notice boss");
31 if (boss != null)
32 {
33 int grade = boss.WorkComplete();
34 Console.WriteLine("Worker Grade=" + grade);
35 }
36
37 }
38 }
39 class Boss
40 {
41 public void WorkStarted() { Console.WriteLine("I'm Boss ,I do not care this:WorkStarted"); }
42 public void WorkProgressing() { Console.WriteLine("I'm Boss ,I do not care this:WorkProgressing"); }
43 ///<summary>
44 /// Worker做完,Boss返回打分结果
45 ///</summary>
46 ///<returns></returns>
47 public int WorkComplete()
48 {
49 Console.WriteLine("Its about time:");
50 return 2;
51 }
52 }
53
54 class Program
55 {
56 static void Main(string[] args)
57 {
58 //生成实例
59 Worker worker = new Worker();
60 Boss boss = new Boss();
61 //将Boss对象放入Worker
62 worker.Advise(boss);
63 //开工
64 worker.DoWork();
65
66 Console.WriteLine("Main:worker completed the work");
67 Console.ReadLine();
68 }
69 }


  这段代码看起来还是很简单的,一个Worker和一个Boss表示一个工人和一个老板的关系,Worker开工后会通知信息到Boss这里,Boss坐在家里就知道,哪个Worker开工了,Worker做完了,调用WorkComplete通知Boss,完工,给我评分,此时Boss返回一个分数。整个过程通过最原始的方法调用完成。

  在ConsoleApplication里运行效果

  

  现在我们换一种方式,使用接口的形式试试  

View Code
 1   ///<summary>
2 /// 通过接口的形式,通知消息
3 ///</summary>
4 class Program
5 {
6 static void Main(string[] args)
7 {
8 Worker worker = new Worker();
9 Boss boss = new Boss();
10 worker.Advise(boss);
11 worker.DoWork();
12
13 Console.WriteLine("Main:worker completed the work");
14 Console.ReadLine();
15 }
16 }
17
18 interface IWorkerEvents
19 {
20 void WorkStarted();
21 void WorkProgressing();
22 int WorkComplete();
23 }
24 class Boss : IWorkerEvents
25 {
26 public void WorkStarted()
27 {
28 Console.WriteLine("I'm Boss ,I do not care this:WorkStarted");
29 }
30
31
32 public void WorkProgressing()
33 {
34 Console.WriteLine("I'm Boss ,I do not care this:WorkProgressing");
35 }
36
37 public int WorkComplete()
38 {
39 Console.WriteLine("Its about time:");
40 return 3;
41 }
42 }
43
44 class Worker
45 {
46 IWorkerEvents events;
47 public void Advise(IWorkerEvents events) { this.events = events;}
48
49 public void DoWork()
50 {
51 Console.WriteLine("Worker:work started,notice boss");
52 if (events != null)
53 events.WorkStarted();
54
55 Console.WriteLine("Worker:work progressing,notice boss");
56 if (events != null)
57 events.WorkProgressing();
58
59 Console.WriteLine("Worker:work complete,notice boss");
60 if (events != null)
61 {
62 int grade = events.WorkComplete();
63 Console.WriteLine("Worker Grade=" + grade);
64 }
65 }
66 }

 

   这里定义了一个IWorkerEvents的接口,接口里声明了三个方法:WorkStarted、WorkProgressing、WorkCompleted,为了在Worker里可以通知到Boss,仍然需要将Boss对象传到Worker内部,不过此时Boss对象不再是死板的自定义方法,而是通过实现Interface的形式,这样一个Worker可以将自己的消息传递给任何实现了IWorkerEvents的对象(有可能是Leader、有可能是Boss的Boss)

  

   但是想想实际情况里,一个Worker头上的却飘这N个Boss,不同级别的Boss,但是我们的DoWork信息不会每一个Boss都关注你,你以为你是什么牛逼的员工啊,因此有的Boss就对这种情况表示厌烦,最大的Boss说,我只要你干完我付钱就好了,你开始没开始不要告诉我。

  好的,既然这样,那就是说,Worker针对不同的Boss要传递不同的消息。这里我们用委托尝试一下  

View Code
 1  delegate void WorkStarted();
2 delegate void WorkProgressing();
3 delegate int WorkCompleted();
4
5 class Boss
6 {
7 public int WorkCompleted()
8 {
9 Console.WriteLine("Its about time:");
10 return 4;
11 }
12 }
13
14 class Worker
15 {
16 ///<summary>
17 /// 对应三个委托
18 ///</summary>
19 public WorkStarted started;
20 public WorkProgressing progressing;
21 public WorkCompleted completed;
22
23 public void DoWork()
24 {
25 //通知Boss,Worker开工了
26 Console.WriteLine("Worker:work started,notice boss");
27 if (started != null)
28 {
29 started();
30 }
31
32
33 Console.WriteLine("Worker:work progressing,notice boss");
34 if (progressing != null) progressing();
35
36 //通知Boss,Workerr做完了,等你打分
37 Console.WriteLine("Worker:work complete,notice boss");
38 if (completed != null)
39 {
40 int grade = completed();
41 Console.WriteLine("Worker Grade=" + grade);
42 }
43
44 }
45 }
46 class Program
47 {
48
49
50
51 static void Main(string[] args)
52 {
53 Worker worker = new Worker();
54 Boss boss = new Boss();
55
56 //只将Boss的WorkCompleted方法注册到Work的Completed方法上
57 worker.completed = new WorkCompleted(boss.WorkCompleted);
58
59
60 worker.DoWork();
61
62
63 Console.WriteLine("Main:worker completed the work");
64 Console.ReadLine();
65 }
66 }


  喔~~~不错,看起来的却可以做到只讲某个事件通知给Boss,其他的事自己一遍干去,Boss不关心你的闲事。

  

  看吧,Boss的耳朵清净了,虽然Work在Started的时候,尝试想通知Boss但是由于Boss的积极拒绝,消息闭塞,无法通知到位,只有Completed会知会Boss,Boss付钱完事。

  不过那如果这个Worker就是非常的自恋,非常的自我感觉良好,很想自己的工作情况,工作进度都让别人知道呢,既然Boss不想听,那我找找其他人或者把我的情况公布出来呢?哈哈,这叫“秀”。我们来秀一下  

View Code
 1  delegate void WorkStarted();
2 delegate void WorkProgressing();
3 delegate int WorkCompleted();
4
5 class Boss
6 {
7 public int WorkCompleted()
8 {
9 Console.WriteLine("Its about time:");
10 return 4;
11 }
12 }
13
14 class Worker
15 {
16 ///<summary>
17 /// 对应三个委托
18 ///</summary>
19 public WorkStarted started;
20 public WorkProgressing progressing;
21 public WorkCompleted completed;
22
23 public void DoWork()
24 {
25 //通知Boss,Worker开工了
26 Console.WriteLine("Worker:work started,notice boss");
27 if (started != null)
28 {
29 started();
30 }
31
32
33 Console.WriteLine("Worker:work progressing,notice boss");
34 if (progressing != null) progressing();
35
36 //通知Boss,Workerr做完了,等你打分
37 Console.WriteLine("Worker:work complete,notice boss");
38 if (completed != null)
39 {
40 int grade = completed();
41 Console.WriteLine("Worker Grade=" + grade);
42 }
43
44 }
45 }
46 class Program
47 {
48
49 static void WorkerStartedWork()
50 {
51 Console.WriteLine("各位注意,我开始工作了哦~~~");
52 }
53 static void WorkerProgressingWork()
54 {
55 Console.WriteLine("各位注意,工作内容很辛苦,我在努力!!!");
56 }
57
58 static void Main(string[] args)
59 {
60 Worker worker = new Worker();
61 Boss boss = new Boss();
62
63 //只将Boss的WorkCompleted方法注册到Work的Completed方法上
64 worker.completed = new WorkCompleted(boss.WorkCompleted);
65 //将两个静态的成员注册给Work,以广播的形式播报
66 worker.started = new WorkStarted(Program.WorkerStartedWork);
67 worker.progressing = new WorkProgressing(Program.WorkerProgressingWork);
68
69 worker.DoWork();
70
71
72 Console.WriteLine("Main:worker completed the work");
73 Console.ReadLine();
74 }
75 }

 

  哈哈,我们添加了两个静态的成员,用于广播这位喜欢秀自己的员工的状态信息。

  

  看到了吧!Worker开始工作时,就通过大厅公布:我开工了!刚做了一会儿还抱怨工作难度,还强调自己的努力。果然够高调的。

  做完后,通知Boss,Boss照样打分。

  这样Worker就可以将自己的信息任意公布啦,也不怕骚扰Boss。

  上面都是使用委托实现的,而且事件注册上去后,就拿不掉了啊,要是我的广播需要暂时停播这个Worker的信息咋办?我想把这个Worker的抱怨信息屏蔽掉,太不和谐了!

  来尝试尝试事件的+/-吧!  

View Code
 1  static void Main(string[] args)
2 {
3 Worker worker = new Worker();
4 Boss boss = new Boss();
5
6 //只将Boss的WorkCompleted方法注册到Work的Completed方法上
7 worker.completed += new WorkCompleted(boss.WorkCompleted);
8
9 //将两个静态的成员注册给Work,以广播的形式播报
10 worker.started += new WorkStarted(Program.WorkerStartedWork);
11 worker.progressing += new WorkProgressing(Program.WorkerProgressingWork);
12
13 worker.DoWork();
14
15 worker.progressing -= new WorkProgressing(Program.WorkerProgressingWork);
16 worker.DoWork();
17 Console.WriteLine("Main:worker completed the work");
18 Console.ReadLine();
19 }


  将Worker的委托字段设为public并以event事件的形式,暴露出来。这样就可以控制大厅是否可以播报某些信息啦!

  

  看起来上面的效果都很合人意。

  下面我们看一些特别的东东。

  如果Worker接受两个Boss的打分,Worker要怎么查看呢?   

View Code
 1      static void Main(string[] args)
2 {
3 Worker worker = new Worker();
4 Boss boss = new Boss();
5 BigBoss bigBoss = new BigBoss();
6 //只将Boss的WorkCompleted方法注册到Work的Completed方法上
7 worker.completed += new WorkCompleted(boss.WorkCompleted);
8 //在加入一个BigBoss的打分
9 worker.completed+=new WorkCompleted(bigBoss.WorkCompleted);
10 //将两个静态的成员注册给Work,以广播的形式播报
11 worker.started += new WorkStarted(Program.WorkerStartedWork);
12 worker.progressing += new WorkProgressing(Program.WorkerProgressingWork);
13
14 worker.DoWork();
15
16 Console.WriteLine("Main:worker completed the work");
17 Console.ReadLine();
18 }


  我们加入了一个BigBoss,同样有一个WorkCompleted方法,并打分9.

  将Boss的WorkCompleted和BigBoss的WorkCompleted同时注册到Worker的WorkCompleted事件上,最后Worker查看评分时,通过GetInvocationList获取所有注册的事件,并输出结果:

  

  干完活后,Worker很满意的看到了Boss和BigBoss的打分,以后知道哪个Boss对他好了.....

  好了,新情况来了,Boss下面监督的可不是只有你一个Worker啊,N的N次方个Worker等着Boss打分呢,如果像上面的这样,等着看分数,这得影响Worker持续工作的啊,会严重影响其他任务的完成进度的。来吧,异步!  

View Code
 1   //通知Boss,Workerr做完了,等你打分
2 Console.WriteLine("Worker:work complete,notice boss");
3 if (completed != null)
4 {
5 foreach (WorkCompleted wc in completed.GetInvocationList())
6 {
7 IAsyncResult res = wc.BeginInvoke(null,null);
8 while (!res.IsCompleted)
9 System.Threading.Thread.Sleep(1);
10 int grade = wc.EndInvoke(res);
11 Console.WriteLine("Grade ="+grade);
12 }
13 }

 

  如果Worker不需要看分数的话,可以直接继续干活了,这里为了查看分数,使用了res.IsCompleted判断调度是否完成,否则等待,最后完成后才可以看到分数。

  再看一下另一种形式,以委托的形式将显示分数的任务分离出来。  

View Code
 1     //通知Boss,Workerr做完了,等你打分
2 Console.WriteLine("Worker:work complete,notice boss");
3 if (completed != null)
4 {
5 foreach (WorkCompleted wc in completed.GetInvocationList())
6 {
7 wc.BeginInvoke(new AsyncCallback(WorkGraded),wc);
8 }
9 }
10
11
12 void WorkGraded(IAsyncResult res)
13 {
14 WorkCompleted wc = (WorkCompleted)res.AsyncState;
15 int grade = wc.EndInvoke(res);
16 Console.WriteLine("显示评分时间:" + DateTime.Now.Minute + "/" + DateTime.Now.Second + "/" + DateTime.Now.Millisecond);
17 Console.WriteLine("Worker Grade=" + grade);
18 }

 

  看看效果吧!

  

  加上最终完整的代码  

View Code
 1   delegate void WorkStarted();
2 delegate void WorkProgressing();
3 delegate int WorkCompleted();
4
5 class Boss
6 {
7 public int WorkCompleted()
8 {
9 System.Threading.Thread.Sleep(3000);
10
11 Console.WriteLine("Its about time:");
12 return 4;
13 }
14 }
15
16 class BigBoss
17 {
18 public int WorkCompleted()
19 {
20 System.Threading.Thread.Sleep(4000);
21 Console.WriteLine("BigBoss :");
22 return 9;
23 }
24 }
25
26 class Worker
27 {
28 ///<summary>
29 /// 对应三个委托
30 ///</summary>
31 public event WorkStarted started;
32 public event WorkProgressing progressing;
33 public event WorkCompleted completed;
34
35 public void DoWork()
36 {
37 //通知Boss,Worker开工了
38 Console.WriteLine("Worker:work started,广播:");
39 if (started != null)
40 {
41 started();
42 }
43
44 Console.WriteLine("Worker:work progressing,广播:");
45 if (progressing != null) progressing();
46
47 //通知Boss,Workerr做完了,等你打分
48 Console.WriteLine("Worker:work complete,notice boss");
49 if (completed != null)
50 {
51 foreach (WorkCompleted wc in completed.GetInvocationList())
52 {
53 wc.BeginInvoke(new AsyncCallback(WorkGraded),wc);
54 }
55 }
56
57 Console.WriteLine("继续干活·~~" + DateTime.Now.Minute + "/" + DateTime.Now.Second + "/" + DateTime.Now.Millisecond);
58
59 }
60
61 void WorkGraded(IAsyncResult res)
62 {
63 WorkCompleted wc = (WorkCompleted)res.AsyncState;
64 int grade = wc.EndInvoke(res);
65 Console.WriteLine("显示评分时间:" + DateTime.Now.Minute + "/" + DateTime.Now.Second + "/" + DateTime.Now.Millisecond);
66 Console.WriteLine("Worker Grade=" + grade);
67 }
68 }
69 class Program
70 {
71
72 static void WorkerStartedWork()
73 {
74 Console.WriteLine("各位注意,我开始工作了哦~~~");
75 }
76 static void WorkerProgressingWork()
77 {
78 Console.WriteLine("各位注意,工作内容很辛苦,我在努力!!!");
79 }
80
81 static void Main(string[] args)
82 {
83 Worker worker = new Worker();
84 Boss boss = new Boss();
85 BigBoss bigBoss = new BigBoss();
86 //只将Boss的WorkCompleted方法注册到Work的Completed方法上
87 worker.completed += new WorkCompleted(boss.WorkCompleted);
88 //在加入一个BigBoss的打分
89 worker.completed+=new WorkCompleted(bigBoss.WorkCompleted);
90 //将两个静态的成员注册给Work,以广播的形式播报
91 worker.started += new WorkStarted(Program.WorkerStartedWork);
92 worker.progressing += new WorkProgressing(Program.WorkerProgressingWork);
93
94 worker.DoWork();
95
96 Console.WriteLine("Main:worker completed the work");
97 Console.ReadLine();
98 }
99 }


   其实我对事件和委托的理解一直也不是非常清楚,所以经常会找一些文章看看,帮助理解,我觉得这本书这里说的还不错,理解起来也比较轻松。希望对大家有用,欢迎讨论一起学习。

 


 

 

  

posted @ 2011-11-05 15:02  liver.wang  阅读(269)  评论(0编辑  收藏  举报