深入理解C#中的委托和事件委托的定义.doc_第1页
深入理解C#中的委托和事件委托的定义.doc_第2页
深入理解C#中的委托和事件委托的定义.doc_第3页
深入理解C#中的委托和事件委托的定义.doc_第4页
深入理解C#中的委托和事件委托的定义.doc_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

深入理解C#中的委托和事件:委托的定义【IT168 专稿】委托和事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易。它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见到委托和事件就觉得心里别(bi)得慌,混身不自在。本文中,我将通过两个范例由浅入深地讲述什么是委托、为什么要使用委托、事件的由来、委托和事件对Observer设计模式的意义、.Net Framework中的委托和事件,对它们的中间代码也做了讨论。 将方法作为方法的参数 我们先不管这个标题如何的绕口,也不管委托究竟是个什么东西,来看下面这两个最简单的方法,它们不过是在屏幕上输出一句问候的话语:public void GreetPeople(string name) / 做某些额外的事情,比如初始化之类,此处略EnglishGreeting(name);public void EnglishGreeting(string name) Console.WriteLine(Morning, + name); 暂且不管这两个方法有没有什么实际意义。GreetPeople用于向某人问好,当我们传递代表某人姓名的name参数,比如说Jimmy,进去的时候,在这个方法中,将调用EnglishGreeting方法,再次传递name参数,EnglishGreeting则用于向屏幕输出 Morning, Jimmy。 现在假设这个程序需要进行全球化,哎呀,不好了,我是中国人,我不明白Morning是什么意思,怎么办呢?好吧,我们再加个中文版的问候方法:public void ChineseGreeting(string name)Console.WriteLine(早上好, + name); 这时候,GreetPeople也需要改一改了,不然如何判断到底用哪个版本的Greeting问候方法合适呢?在进行这个之前,我们最好再定义一个枚举作为判断的依据:public enum LanguageEnglish, Chinesepublic void GreetPeople(string name, Language lang)/做某些额外的事情,比如初始化之类,此处略swith(lang)case Language.English:EnglishGreeting(name);break;case Language.Chinese:ChineseGreeting(name);break; OK,尽管这样解决了问题,但我不说大家也很容易想到,这个解决方案的可扩展性很差,如果日后我们需要再添加韩文版、日文版,就不得不反复修改枚举和GreetPeople()方法,以适应新的需求。在考虑新的解决方案之前,我们先看看GreetPeople的方法签名:public void GreetPeople(string name, Language lang) 我们仅看 string name,在这里,string 是参数类型,name 是参数变量,当我们赋给name字符串jimmy时,它就代表jimmy这个值;当我们赋给它张子阳时,它又代表着张子阳这个值。然后,我们可以在方法体内对这个name进行其他操作。哎,这简直是废话么,刚学程序就知道了。 如果你再仔细想想,假如GreetPeople()方法可以接受一个参数变量,这个变量可以代表另一个方法,当我们给这个变量赋值 EnglishGreeting的时候,它代表着 EnglsihGreeting() 这个方法;当我们给它赋值ChineseGreeting 的时候,它又代表着ChineseGreeting()方法。 我们将这个参数变量命名为 MakeGreeting,那么不是可以如同给name赋值时一样,在调用 GreetPeople()方法的时候,给这个MakeGreeting 参数也赋上值么(ChineseGreeting或者EnglsihGreeting等)?然后,我们在方法体内,也可以像使用别的参数一样使用 MakeGreeting。但是,由于MakeGreeting代表着一个方法,它的使用方式应该和它被赋的方法(比如ChineseGreeting) 是一样的,比如:MakeGreeting(name); 好了,有了思路了,我们现在就来改改GreetPeople()方法,那么它应该是这个样子了:public void GreetPeople(string name, * MakeGreeting)MakeGreeting(name); 注意到 * ,这个位置通常放置的应该是参数的类型,但到目前为止,我们仅仅是想到应该有个可以代表方法的参数,并按这个思路去改写GreetPeople方法,现在就出现了一个大问题:这个代表着方法的MakeGreeting参数应该是什么类型的? NOTE:这里已不再需要枚举了,因为在给MakeGreeting赋值的时候动态地决定使用哪个方法,是ChineseGreeting还是 EnglishGreeting,而在这个两个方法内部,已经对使用morning还是早上好作了区分。 聪明的你应该已经想到了,现在是委托该出场的时候了,但讲述委托之前,我们再看看MakeGreeting参数所能代表的 ChineseGreeting()和EnglishGreeting()方法的签名:public void EnglishGreeting(string name)public void ChineseGreeting(string name) 如同name可以接受String类型的true和1,但不能接受bool类型的true和int类型的1一样。MakeGreeting的 参数类型定义 应该能够确定 MakeGreeting可以代表的方法种类,再进一步讲,就是MakeGreeting可以代表的方法 的 参数类型和返回类型。于是,委托出现了:它定义了MakeGreeting参数所能代表的方法的种类,也就是MakeGreeting参数的类型。 NOTE:如果上面这句话比较绕口,我把它翻译成这样:string 定义了name参数所能代表的值的种类,也就是name参数的类型。 本例中委托的定义:public delegate void GreetingDelegate(string name); 可以与上面EnglishGreeting()方法的签名对比一下,除了加入了delegate关键字以外,其余的是不是完全一样? 现在,让我们再次改动GreetPeople()方法,如下所示:public void GreetPeople(string name, GreetingDelegate MakeGreeting)MakeGreeting(name); 如你所见,委托GreetingDelegate出现的位置与 string相同,string是一个类型,那么GreetingDelegate应该也是一个类型,或者叫类(Class)。但是委托的声明方式和类却完全不同,这是怎么一回事?实际上,委托在编译的时候确实会编译成类。因为Delegate是一个类,所以在任何可以声明类的地方都可以声明委托。更多的内容将在下面讲述,现在,请看看这个范例的完整代码:using System;using System.Collections.Generic;using System.Text;namespace Delegate /定义委托,它定义了可以代表的方法的类型public delegate void GreetingDelegate(string name);class Program private static void EnglishGreeting(string name) Console.WriteLine(Morning, + name);private static void ChineseGreeting(string name) Console.WriteLine(早上好, + name);/注意此方法,它接受一个GreetingDelegate类型的方法作为参数private static void GreetPeople(string name, GreetingDelegate MakeGreeting) MakeGreeting(name);static void Main(string args) GreetPeople(Jimmy Zhang, EnglishGreeting);GreetPeople(张子阳, ChineseGreeting);Console.ReadKey(); 输出如下: Morning, Jimmy Zhang 早上好, 张子阳 我们现在对委托做一个总结: 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。C#的委托:国王与大臣的故事【IT168 专稿】委托(delegate)是引用类型,它可以引用内存地址的方法把方法当参数来传递。其的原理是,把目的(委托的声明)告诉委托大臣(代理者),让大臣(代理者)自已来定义他需要怎么去做(和委托具有相同签名的具体实现方法)。 对委托进行讲解之前。我先说一个故事,我只记得大概的内容。然后我用委托去实现这个故事。 从前有一个国王King ,他有三个大臣(ministerA,ministerB,ministerC),他想考考这三个大臣中哪个是人才哪个是饭桶。于是有一天King对三个大臣说,我给你们每个人十个金币,你们离开王宫一年,看看你们可以用这十个金币为我带来些什么。三个大臣听完就后,就离开了王宫。 一年过去了,三个大臣分别回来了。大臣ministerA带回来了100颗金币,他对国王说:我出去之后就在一些地方做起了生意,生意越做越大,现在金币有100颗了;大王听后非常高兴,给ministerA另外加多100颗金币的奖励。 第2天,ministerB回来了,给国王带来了是一些本国没有的货物,国王也奖励了他10颗金币。 第3天,.ministerC回来了,给国王带来了是原来的十个金币,他对国王说:这一年他没有离开本国,为了表示对国王的敬爱,10个都保持都完好无缺.最后国王知道哪个是饭桶了,将ministerC变成平民。 从这个故事可以看出,国王委托了大臣去做一些事(委托的声明)。大臣们返回了不同的东西(委托声明中的返回值)。国王对大臣做的这些事进行了处理(委托可以让方法像参数一样传递给一个方法处理)。国王事先是不知道他们是返回什么东西的。但国王要他们有结果给他。我们就当国王大臣的返回的东西叫MinisterReturns吧class MinisterReturns/虽然这里什么都没有,其实你可以把它理解成是一个子类的容器/故事中第一个大臣和第3个大臣返回的是金币,所以我这里将金币由MinisterReturns来派生吧class goldCoin : MinisterReturnsprivate int _coinsAmount;public goldCoin(int coinsAmount)this._coinsAmount = coinsAmount;public int coinsAmountgetreturn _coinsAmount;故事中第2个大臣是带来了货物。class goods : MinisterReturnsprivate string _goods = 精美的商品;public string Goodsgetreturn _goods; 在我们定义好了大臣返回的东西后,我们要定义国王这个类了,这个故事中国王主要对委托大臣做的事情的结果进行处理.这里也引出了委托的作用,委托可以将方法像参数一样传递给另一个方法,然后KING只要对参数进行处理就行了,所以在定义king之前我们先定义好一个委托先。delegate MinisterReturns MinisterOneYearDo(); 由于每一个大臣得到的都是10个金币,所以没必要传参数进去了。下面我们来定义国王要做的事情,国王要做的事情就是要处理委托做完事后的结果。public static void handleMinisterOneyearDo(MinisterOneYearDo action) 结果是对大臣A奖励,对大臣B奖励,对大臣C处罚。class kingpublic static string KingsOrder = 让三个大臣用10个金币在王宫外一年的时间给国王带来一些东西.;public static void handleMinisterOneyearDo(MinisterOneYearDo action) MinisterReturns minreturns = action(); if (minreturns is goldCoin)switch (goldCoin)minreturns).coinsAmount)case 100:Console.WriteLine(king非常高兴大臣1的表现,奖多100个金币);break;case 10:Console.WriteLine(king觉得这个是饭桶,变为平民);break;default:break;if (minreturns is goods)Console.WriteLine(king非常高兴大臣2的表现,奖多10个金币);下面是三个大臣根据委托的签名定义的方法,注意的是我们定义的委托签名是要返回MinisterReturns,但下面三个大臣返回的东西都不一样。为什么可以这样做呢? 我们在下面结果运行后在进行解析:class MinisterApublic static goldCoin MinisterAOneYearDo()goldCoin coins = new goldCoin(100);Console.WriteLine(我是大臣A,我给国王带来了100颗金币.);return coins;class MinisterBpublic static goods MinisterBOneYearDo()goods GOODS = new goods();Console.WriteLine(我是大臣B,我给国王带来了本国没有的精美货物.);return GOODS; class MinisterCpublic static goldCoin MinisterCOneYearDo()goldCoin coins = new goldCoin(10);Console.WriteLine(我是大臣C,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论