第二章:C#委托和事件
第一节:委托
相信大家在现实生活中,经常听到“委托”这个词汇,尤其在涉及官司的时候,经常听到“委托律师”等这样的字眼。所以,单纯就”委托“这个词而言,指的就是命令,发命令的人自己不做事,而让委托的对象去做事。同理,在程序里面,委托只是存储了各个方法的地址,它自己本身其实是什么都不做的。
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
1 private delegate void GreetingPeopleDelegate(); 2 3 static void Main(string[] args) 4 { 5 GreetPeople(EnglishGreeting); 6 GreetPeople(ChineseGreeting); 7 8 Console.ReadLine(); 9 } 10 11 private static void GreetPeople(GreetingPeopleDelegate greetingPeopleDelegate) 12 { 13 greetingPeopleDelegate(); 14 } 15 16 private static void EnglishGreeting() 17 { 18 Console.WriteLine("Good morning!"); 19 } 20 21 private static void ChineseGreeting() 22 { 23 Console.WriteLine("早上好!"); 24 }
输出结果:
Good morning!
早上好!
从上面的例子可以看出,委托可以做到把函数当作函数参数一样传递,即:可以将业务逻辑作为参数传递,极大提高了函数的通用性。
*扩展:多播委托
使用委托可以将多个方法绑定到同一个委托变量,当调用此变量时(这里用“调用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。
现在我们举个有趣的例子,让大家更好理解多播委托的含义。
故事背景:在某次战役中,主公要求指挥官诸葛亮要指挥自己的部下关羽和张飞去攻打曹军中军大帐,而同时要指挥赵子龙去后方偷袭粮草大营。那么这个简单的故事,如何用程序描述呢?
首先,故事中的委托,并非单一的,而是好几件事都需要委托,于是这里有一个新的概念——多播委托。
1. 建立General(将军)类
1 public class General 2 { 3 private string _name; 4 5 public General(string name) 6 { 7 this._name = name; 8 } 9 10 public string Name 11 { 12 get { return this._name; } 13 } 14 15 public virtual void Execute() 16 { 17 Console.WriteLine("I have nothing to do yet."); 18 } 19 }
2. 建立Attacker(攻击者)类,继承General类
1 public class Attacker : General 2 { 3 public Attacker(string name) 4 : base(name) { } 5 6 public override void Execute() 7 { 8 Console.WriteLine(string.Format("{0} is attacking the enemy!", this.Name)); 9 } 10 }
3. 建立Intercepter(偷袭者)类
1 public class Intercepter : General 2 { 3 public Intercepter(string name) 4 : base(name) { } 5 6 public override void Execute() 7 { 8 Console.WriteLine(string.Format("{0} is intercepting the reinforcement!", this.Name)); 9 } 10 }
4. 建立Commander(指挥官)类
1 public class Commander : General 2 { 3 private delegate void MilitaryPlan(); 4 5 public Commander(string name) 6 : base(name) { } 7 8 public void MakeMilitaryPlan(string[] attackerNames, string[] intercepterNames) 9 { 10 MilitaryPlan militaryPlan = new MilitaryPlan(this.AcceptLordInstructions); 11 12 foreach (string attackerName in attackerNames) 13 { 14 Attacker attacker = new Attacker(attackerName); 15 militaryPlan += attacker.Execute; 16 } 17 foreach (string intercepterName in intercepterNames) 18 { 19 Intercepter intercepter = new Intercepter(intercepterName); 20 militaryPlan += intercepter.Execute; 21 } 22 23 militaryPlan(); 24 }
调用方法:
1 static void Main(string[] args) 2 { 3 Commander commander = new Commander("诸葛亮"); 4 commander.MakeMilitaryPlan(new string[] { "关羽", "张飞" }, new string[] { "赵云" }); 5 6 Console.ReadLine(); 7 }
运行结果:
诸葛亮 accepted the instructions from lord
关羽 is attacking the enemy!
张飞 is attacking the enemy!
赵云 is intercepting the reinforcement!
扩展: 假设主公要求的指挥官不是诸葛亮,而是凤雏庞统,庞统下达的命令是让马超和黄忠去袭击曹军中军大帐,而让魏延去后方偷袭粮草大营,只需要改一下传参即可:
1 static void Main(string[] args) 2 { 3 Commander commander = new Commander("庞统"); 4 commander.MakeMilitaryPlan(new string[] { "马超", "黄忠" }, new string[] { "魏延" }); 5 6 Console.ReadLine(); 7 }
运行结果:
庞统 accepted the instructions from lord
马超 is attacking the enemy!
黄忠 is attacking the enemy!
魏延 is intercepting the reinforcement!