先骂个街,天儿太闷了……
随手复习一下委托,delegate 是一种函数指针,是 .net 提供的一种安全的函数指针,翻译的也很贴切,像是委托人,又像代理人,通过“委托”来执行一些函数而不是直接调用它。因为 C# 中委托被实现为指针链表,所以委托可以加入多个函数,一次性一块儿执行。
举个花生:小明(中国教育中最频繁出镜的绝对明星,不知为什么,我脑子里直觉般闪现第一个名字就是它,我Kao)要给他妈买酱油(貌似这个例子在多年前我自己的帖子里出现过),妈妈对小明的调用就表示为:
1 public class 妈妈 2 { 3 酱油 Get酱油() 4 { 5 var 孩子 = new 小明(); 6 retu 小明.打酱油(); 7 } 8 }
当妈妈需要酱油时候,可以随时召唤小明去卖,那么如果需要盐呢、醋呢,假设 小明 都提供这样的方法,那么妈妈调用时候不得不这样:
1 public class 妈妈 2 { 3 调料 Get调料() 4 { 5 var 多种调料 = new 调料集合(); 6 var 孩子 = new 小明(); 7 调料集合.Add(小明.打酱油()); 8 调料集合.Add(小明.买醋()); 9 调料集合.Add(小明.买盐()); 10 11 return 多种调料; 12 } 13 }
事情到了现在,有两个很明显的问题:
1. 妈妈直接对小明进行了操作,这不是聪明的编码方式,因为如果妈妈还有闺女小红呢?让小红再去买东西就需要修改大量的妈妈类中的代码,显然很二。
2. 代码中规定了方法里只能调用小明三个技能,再多加两个或少买一个呢,就必须重新修改源代码了,所以不能做到动态的增减技能。
说到这里好像跑题去谈如何构建程序了,显然我还没到那个水平,回到委托,如果使用委托,至少可以同时解决这两个主要问题,因为:
1. 委托是“中间人”,妈妈可以全心关注对委托的控制,比如增加和减少要购买的东西
2. 委托是“相对抽象”的,妈妈通过委托既可以选择小明去买,也可以选择小红去买,一定程度上的解耦
用委托改一下,依旧忽略细节,只领会精神:
1 public class 妈妈 2 { 3 delegate 调料 买调料委托(); 4 private 买调料委托 妈妈让孩子去买调料; 5 } 6 7 public static class 小明 8 { 9 public static 调料 打酱油(){} 10 public static 调料 买醋(){} 11 public static 调料 买盐(){} 12 } 13 14 public static class 小红 15 { 16 public static 调料 打酱油(){} 17 public static 调料 买米(){} 18 public static 调料 买油(){} 19 }
妈妈定义了一个“买调料”的委托,只要孩子有和这个委托签名一致的技能,妈妈就可以使用。有了这个基础,妈妈再考虑买调料时候就人性化的多,比如 1 日要买酱油、醋和米,就可以这样:
1 妈妈让孩子去买调料 = new 买调料委托(小明.打酱油); 2 妈妈让孩子去买调料 += 小明.买醋(); 3 妈妈让孩子去买调料 += 小红.买米(); 4 妈妈让孩子去买调料();
妈妈把分属于两个孩子的三个技能添加到了委托,妈妈只需要运行这个委托,就可以运行一次买到三个东西,2 日妈妈不再需要买米而需要买盐时,就可以这样:
1 妈妈让孩子去买调料 -= 小红.买米(); 2 妈妈让孩子去买调料 += 小红.买盐();
从语法上来说我觉得已经比较人性化了,下面放上两个简单的示意代码,描述一下对委托的增减:
1 delegate void OnEventDelegate(string text); 2 OnEventDelegate OnEventHandler; 3 4 private void button1_Click(object sender, EventArgs e) 5 { 6 if (OnEventHandler == null) 7 { 8 OnEventHandler = new OnEventDelegate(ShowLabel1); 9 OnEventHandler += ShowLabel2; 10 OnEventHandler += ShowLabel3; 11 OnEventHandler += ShowLabel4; 12 13 MessageBox.Show(string.Format("delegate object count: {0}", OnEventHandler.GetInvocationList().Count())); 14 } 15 } 16 17 private void button2_Click(object sender, EventArgs e) 18 { 19 if (null != OnEventHandler) 20 { 21 foreach (var method in OnEventHandler.GetInvocationList()) 22 { 23 MessageBox.Show(string.Format("delegate has method cout: {0}, now remove : {1}", OnEventHandler.GetInvocationList().Count(), method.Method.Name)); 24 25 OnEventHandler -= (OnEventDelegate)method; 26 27 if (null == OnEventHandler) 28 { 29 MessageBox.Show("delegate remove all method"); 30 break; 31 } 32 } 33 } 34 } 35 36 private void button3_Click(object sender, EventArgs e) 37 { 38 var timeString = DateTime.Now.Second.ToString(); 39 OnEventHandler(timeString); 40 }