解惑答疑:C#委托和事件

开发 后端
为什么会有委托?委托有什么好处?本文就解答了学习C#委托和事件过程中的一些问题。

相信很多人一直为C#委托和事件所困惑,尤其是C#的初学者,学到这一部分会感觉比较困难,很有可能就放弃了,而且.NET对委托和事件封装得挺好,一般都不怎么用到自定义的委托和事件,所以放弃学习该技术就有了借口!

网上也有不少此类的文章,最具代表性的是张子阳的C#中的委托和事件以及C#中的委托和事件(续)这两篇,写得的确很好,得到很多读者的赞赏,但我看评论,还是发现了些问题,因为有不少读者是看了一遍又一遍,每次感觉都蛮好,可是隔一段时间,对“委托和事件”又迷糊了,于是又来看!我真搞不懂,为什么会出现这种情况!后来想想,文章虽好,但总结的地方没有把重点列出来;再者,读者跟着作者的思路,的确能把文章看懂,但是读者自己不得要领,没有真正弄明白,因此就出现了上面提到的状况!

C#委托和事件真的难吗,其实不然。要搞懂它,第一,要看你的理解能力;第二,要看你怎么理解它。如果你觉得理解起来比较困难,那我们可以换种理解方式,也许能很好地理解它了!其实委托和事件的确不难,大牛级别的甚至都不屑写此类文章!

为什么会有委托?

委托其实就是个方法指针,拥有同样参数和返回值的任何方法都能传给委托;委托能够消除条件分支语句,不需要根据if、case这些语句来判断具体调用哪个方法!而委托又是从观察者模式演化而来,这里推荐阅读TerryLee的这篇观察者模式文章。

前面说的的就算不理解也不要紧,关键是理解方法、委托、事件之间的关系。可以这样说,方法是“委托”给委托的,而委托是“委托”给事件的。可以将事件看成是委托的一个容器,里面可以加一连串的委托!这样来理解,那所有的事情就都解决了!

当然,我们都是在某个方法中触发事件,事件将其交给委托,委托再交给方法,方法再进行实际的操作,与上面的步骤刚好相反!其实触发事件的目的就是触发具体方法!

再来说说委托的好处(上面没举例子),比如你开发了一个电子商务平台,后台有管理商品的功能,而商品信息有七八列或者更多,包括编号、商品名称、价格、上架时间等等,该信息又能根据任意一列来进行排序!如果没有委托,我们将根据点击某列所产生的信息,将这信息传给某个排序方法,而这个排序方法会接受传来的信息作为参数,再根据内部的分支语句if、case等来判断具体采用哪个排序方法,这样的话,逻辑变复杂,这过程当中还要做很多无用功(因为很有可能要进行多次判断才能找到要真正执行的方法),而且如果我们将来再增加列,又得增加分支语句,违背了“开放—封闭”原则,维护起来比较麻烦!有了委托,我们不需要传递任何参数,直接将具体方法传给委托即可,增加列则只要增加一个新方法,爽!我们完全可以通过委托来调用方法,那为什么还要事件呢?事件其实是对委托进行一种限制,使其无法使用“=”赋值运算符(如果使用则在编译时产生错误),只能使用“+=”或者“-=”运算符,这就防止了程序员误将原先的委托链给覆盖掉,另外delegate类从MulticastDelegate(多路广播委托)继承而来,所以可以将多个委托赋给同一个事件!

最后,列一串代码把上面的概念理清一下

  1. class Program  
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         XiaoBai xiaobai = new XiaoBai();  
  6.         //Google公司  
  7.         ItCompany google = new ItCompany("谷歌中国""CTO", xiaobai);  
  8.         //微软公司  
  9.         ItCompany microsoft = new ItCompany("微软中国""架构师", xiaobai);  
  10.  
  11.         //花旗银行  
  12.         FinanceCompany AmericaBank = new FinanceCompany("花旗银行""金融分析师", xiaobai);  
  13.  
  14.         //委托的好处,可以应用于不同的类的不同方法  
  15.         //方法“委托”给委托,委托“委托”给事件  
  16.         //委托类型与事件声明时的委托类型相同  
  17.         //因为是传引用,所以方法后面不能带括号,带括号则是调用方法了  
  18.         //一个委托可以搭载多个方法,一个事件则拥有一个委托链  
  19.         xiaobai.Update += new TheEventHandler(google.ComeToItCompany);  
  20.         xiaobai.Update += new TheEventHandler(microsoft.ComeToItCompany);  
  21.         xiaobai.Update += new TheEventHandler(AmericaBank.ComeToFinanceCompany);  
  22.  
  23.         xiaobai.SubjectState = "我小白过来应聘职位啦!";  
  24.  
  25.         //发出通知,触发事件  
  26.         xiaobai.Notify();  
  27.  
  28.         //以下代码与上面相似  
  29.         XiaoHua xiaohua = new XiaoHua();  
  30.  
  31.         ItCompany microsoft2 = new ItCompany("微软总公司""CEO", xiaohua);  
  32.  
  33.         FinanceCompany ChinaBank = new FinanceCompany("中国央行""财务部总经理", xiaohua);  
  34.  
  35.         xiaohua.Update += new TheEventHandler(microsoft2.ComeToItCompany);  
  36.         xiaohua.Update += new TheEventHandler(ChinaBank.ComeToFinanceCompany);  
  37.  
  38.         xiaohua.SubjectState = "我小华过来应聘职位啦!";  
  39.  
  40.         xiaohua.Notify();  
  41.  
  42.         Console.ReadLine();  
  43.     }  
  44. }  
  45.  
  46. //通知者接口  
  47. interface Subject  
  48. {  
  49.     void Notify();  
  50.  
  51.     string SubjectState  
  52.     {  
  53.         get;  
  54.         set;  
  55.     }  
  56. }  
  57.  
  58. //事件处理程序的委托,相当于一个类(在编译成IL后确确实实是类)或者方法指针,与常规类定义不同,带参数和返回值  
  59. delegate void TheEventHandler();  
  60.  
  61. //小白  
  62. class XiaoBai : Subject  
  63. {  
  64.     //声明一事件Update,类型为委托TheEventHandler  
  65.     public event TheEventHandler Update;  
  66.  
  67.     private string action;  
  68.  
  69.     //用Notify方法触发事件  
  70.     public void Notify()  
  71.     {  
  72.         Update();  
  73.     }  
  74.  
  75.     public string SubjectState  
  76.     {  
  77.         get { return action; }  
  78.         set { action = value; }  
  79.     }  
  80. }  
  81.  
  82. //小华  
  83. class XiaoHua : Subject  
  84. {  
  85.     //声明一事件Update,类型为委托TheEventHandler  
  86.     public event TheEventHandler Update;  
  87.  
  88.     private string action;  
  89.  
  90.     //用Notify方法触发事件  
  91.     public void Notify()  
  92.     {  
  93.         Update();  
  94.     }  
  95.  
  96.     public string SubjectState  
  97.     {  
  98.         get { return action; }  
  99.         set { action = value; }  
  100.     }  
  101. }  
  102.  
  103. //IT行业  
  104. class ItCompany  
  105. {  
  106.     private string companyname;  
  107.     private string job;  
  108.     private Subject sub;  
  109.  
  110.     public ItCompany(string _companyname, string _job, Subject _sub)  
  111.     {  
  112.         companyname = _companyname;  
  113.         job = _job;  
  114.         sub = _sub;  
  115.     }  
  116.  
  117.     //参数和返回值与委托TheEventHandler一致  
  118.     public void ComeToItCompany()  
  119.     {  
  120.         Console.WriteLine("{0} {1}: 来我们公司做{2}!", sub.SubjectState, companyname, job);  
  121.     }  
  122. }  
  123.  
  124. //金融行业  
  125. class FinanceCompany  
  126. {   
  127.     private string companyname;  
  128.     private string job;  
  129.     private Subject sub;  
  130.  
  131.     public FinanceCompany(string _companyname, string _job, Subject _sub)  
  132.     {  
  133.         companyname = _companyname;  
  134.         job = _job;  
  135.         sub = _sub;  
  136.     }  
  137.  
  138.     //参数和返回值与委托TheEventHandler一致  
  139.     public void ComeToFinanceCompany()  
  140.     {  
  141.         Console.WriteLine("{0} {1}: 来我们公司做{2}!", sub.SubjectState, companyname, job);  
  142.     }  

通过以上总结,我相信大家对C#委托和事件应该可以更好地理解了!当然,委托的知识不止这些,还会用到检查空值、异常处理和多线程处理等等,这篇文章仅在解惑(我也不高兴浪费太多的时间来具体讲解)!如果你想更好地掌握委托和事件,可以看下上面提到的张子阳的两篇文章或者买本《C#本质论》仔细研读;如果你想了解观察者模式,可以看下上面提到的TerryLee那篇文章;如果你还没有学习设计模式或者刚刚开始学习,我建议阅读《大话设计模式》;如果你学习设计模式有一段时间了,我建议阅读《设计模式:基于C#的工程化实现及扩展》!祝各位程序员好运!

【编辑推荐】

  1. 总结C#语言命名规范
  2. C#反射相关知识学习
  3. 大话F#和C#:是否会重蹈C#失败的覆辙?
  4. 总结和学习C#接口
  5. 学习C#程序有感
责任编辑:book05 来源: hi.baidu
相关推荐

2009-08-27 16:53:01

C#委托C#事件

2009-10-09 09:07:40

C#委托和事件

2009-08-18 10:54:17

C#事件和委托

2009-09-08 15:28:24

C#委托

2009-08-03 13:23:04

C#编程组件-事件-委托

2009-08-04 13:53:58

C#委托类C#事件

2013-03-19 09:48:38

C#

2011-06-30 10:28:50

C#开发

2009-07-20 10:36:29

什么是JDBC

2009-08-26 14:48:05

C#委托与事件

2009-08-20 18:11:08

C#异步委托

2009-08-18 10:35:26

C#委托

2009-09-01 18:36:35

C#委托实例

2011-04-22 09:14:26

C#委托

2009-08-20 18:37:52

委托C#异步委托

2009-08-04 09:56:46

C#事件处理自定义事件

2011-05-20 17:50:45

C#

2010-09-14 14:05:42

C#委托

2009-08-31 09:20:37

C#事件注册和注销

2010-12-22 10:21:17

C#基础
点赞
收藏

51CTO技术栈公众号