继续上一篇:11委托演绎中国足球队打进世界杯
□ 含有相同参数列表的各种处理球方法不变,把带委托参数的方法放到一个类中
1: namespace ConsoleApplication11
2: {3: class Program
4: {5: static void Main(string[] args)
6: {7: GameManager gm = new GameManager();
8: gm.Game("球",PassBall);
9: Console.WriteLine();10: gm.Game("球",TransferpBall);
11: Console.ReadKey(); 12: } 13: 14: private static void PassBall(string ball)
15: {16: Console.Write("传" + ball);
17: } 18: 19: private static void StopBall(string ball)
20: {21: Console.Write("停/接" + ball);
22: } 23: 24: private static void TransferpBall(string ball)
25: {26: Console.Write("转移" + ball);
27: } 28: 29: private static void RunBall(string ball)
30: {31: Console.Write("带" + ball);
32: } 33: 34: private static void ScoreBallByHead(string ball)
35: {36: Console.Write("头"+ball + "射门");
37: } 38: 39: private static void ScoreBallByInnerFeet(string ball)
40: {41: Console.Write("推射" + ball + "射门");
42: } 43: 44: private static void ScoreBallByOuterFeet(string ball)
45: {46: Console.Write("外脚背射" + ball + "门");
47: } 48: }49: public delegate void PlayBall(string ball);
50: 51: public class GameManager
52: {53: public void Game(string ball, PlayBall playBallDelegate)
54: { 55: playBallDelegate(ball); 56: } 57: } 58: }
□ 采用多播委托,把多个方法绑定到同一个委托变量
1: GameManager gm = new GameManager();
2: PlayBall del = PassBall; 3: del += RunBall;4: gm.Game("球",del);
5: Console.ReadKey();
□ 把委托封装到类中
1: class Program
2: {3: static void Main(string[] args)
4: {5: GameManager gm = new GameManager();
6: gm.delegate1 = ScoreBallByHead; 7: gm.delegate1 += ScoreBallByInnerFeet;8: gm.Game("球", gm.delegate1);
9: Console.ReadKey(); 10: } 11: ..... 12: }13: public delegate void PlayBall(string ball);
14: 15: public class GameManager
16: {17: public PlayBall delegate1;
18: public void Game(string ball, PlayBall playBallDelegate)
19: { 20: playBallDelegate(ball); 21: } 22: }
还可以把gm.Game("球", gm.delegate1)改成类似gm.Game("球"),达到这样的效果,需要在Game()方法体内让委托变量来执行方法。
□ 直接调用类的实例方法,不带委托参数
1: class Program
2: {3: static void Main(string[] args)
4: {5: GameManager gm = new GameManager();
6: gm.delegate1 = PassBall; 7: gm.delegate1 += ScoreBallByOuterFeet;8: gm.Game("球");
9: Console.ReadKey(); 10: } 11: ...... 12: }13: public delegate void PlayBall(string ball);
14: 15: public class GameManager
16: {17: public PlayBall delegate1;
18: public void Game(string ball)
19: {20: if (delegate1 != null)
21: { 22: delegate1(ball); 23: } 24: } 25: } 26:
依然存在的问题是:
1、把委托字段成delegate1声明成public,客户端可以随意赋值,破坏了对象的封闭原则。
2、如果把委托字段成delegate1声明成private,客户端就不能调用。
3、给委托赋值用=,给委托注册用+=,好像也不是很统一。
□ 事件就此登上历史舞台
1: class Program
2: {3: static void Main(string[] args)
4: {5: GameManager gm = new GameManager();
6: gm.event1 = PassBall; 7: gm.event1 += ScoreBallByOuterFeet;8: gm.Game("球");
9: Console.ReadKey(); 10: } 11: ...... 12: }13: public delegate void PlayBall(string ball);
14: 15: public class GameManager
16: {17: public event PlayBall event1;
18: public void Game(string ball)
19: { 20: event1(ball); 21: } 22: } 23:
事件可以看成:
为委托类型量身定制的属性。
使用事件的好处:
限制含有事件类型的能力,即事件应该由事件的发布者触发,而不应该由事件的客户端来触发。
□ 事件的一个例子
1: namespace ConsoleApplication12
2: {3: class Program
4: {5: static void Main(string[] args)
6: {7: Publisher publisher = new Publisher(2);
8: Subscriber subscriber = new Subscriber();
9: 10: publisher.NumberChanged += new NumberChangedEventHandler(subscriber.OnNumberChanged);
11: publisher.DoSth(); 12: Console.ReadKey(); 13: } 14: } 15: 16: //定义委托
17: public delegate void NumberChangedEventHandler(int count);
18: 19: //事件发布者
20: public class Publisher
21: {22: private int count;
23: public event NumberChangedEventHandler NumberChanged;
24: 25: public Publisher(int count)
26: {27: this.count = count;
28: } 29: 30: public void DoSth()
31: {32: Console.WriteLine("我是发布者,我开始工作了~~");
33: if (NumberChanged != null)
34: { 35: count++; 36: NumberChanged(count); 37: } 38: } 39: } 40: 41: //定义事件订阅者
42: public class Subscriber
43: {44: public void OnNumberChanged(int count)
45: {46: Console.WriteLine("我知道了,现在的数量是:" + count);
47: } 48: } 49: } 50:
关于事件的小结:
● 在委托的前面加上关键字event,就变成了事件public
event NumberChangedEventHandler NumberChanged
●
一旦声明成事件,只能通过事件所在类(发布者)的方法来触发事件:publisher.DoSth();
订阅者的和发布者的惯例:
● 如果想运行订阅者的方法触发事件public delegate
void NumberChangedEventHandler(int
count),从而让订阅者也触发相应的方法,那订阅者的方法OnNumberChanged(int
count)的参数列表和事件一致,并且是在事件变量NumberChanged前面加上On变成OnNumberChanged。
● 订阅者是通过publisher.NumberChanged += new NumberChangedEventHandler(subscriber.OnNumberChanged)绑定到发布者的事件,建立触发关联的。
参考资料:
※ 《.NET之美》--张子阳,感谢写了这么好的书!
原文:http://www.cnblogs.com/darrenji/p/3606678.html