首页 > 代码库 > 对张子扬显示的两篇委托和事件说得很透文章读后的思考

对张子扬显示的两篇委托和事件说得很透文章读后的思考

第一篇 C#中的委托和事件

http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx
 

第二篇 C#中的委托和事件(续)

http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-Advanced.aspx
 
 
这是两篇目前为止,我读过的介绍委托和事件以及异步调用最简明清晰文章,作者通过非常有节奏的“标题”->“问题”->“思路”->“实现”->“讲解”的结构,分步骤一步一步地将委托和事件的实现、应用与原理阐述得非常清楚,并且在行文期间将自己有趣的思考过程通过生动的语言表达了出来,使人读起来越发的感兴趣,以下就是我读过这两篇文章以后,对委托、事件、异步调用一些新的理解角度。
 
首先要引用作者文中的一个总结语:
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
 
我对这句话的的理解是,可以从clr-via 设计的理念去阐述,委托定义了一个方法的类型,代表一类方法。
对,没错,就是各种命名的同参数列表的方法进行归类,归类后就可以很方便的放在一个List<T>中,那么在调用的时候,就可以简单地使用调用delegate的一个实例成员,来调用订阅了这一委托实例的这一组同类型方法,因为他们需要的参数列表都是相同的嘛~。
 
c#委托到底是怎么个事儿呢?
 
先讲个故事,传说中有这么一个市,市里有100个手工艺人,这100个人里每个人都有用某种指定的材料和工具做出自己最擅长的作品(订阅函数),这个时候,你发现这些工具和材料都有渠道可以找到,于是,你就想如果把材料变成作品,该有多大市场啊,本着商人逐利的思维,你对外宣布了这些手工艺人可以找你要材料和工具去制作他自己的作品。你能搜罗到的材料和工具,就是订阅函数的参数列表,然后你可以往外发的这个事,就可以抽象为一种委托类型了,随便起个名字吧delegate SendToolandMaterial(Tools,Material);,而你告诉外边儿凡是能做作品的工匠,就能找你要工具和材料的这个事儿,就是类中的委托实例public SendToolandMaterial  sendToolMaterial;然后,你知道要做作品得发材料工具了,也把你要发材料和工具这个事儿告诉外边儿了,于是开始有人告诉你他要工具材料,因为他能做这种材料的作品,手艺人找你要材料和工具的这个行为,就是“+=”订阅操作。
然后在你发了一阵工具和材料之后(也有可能一个人都没发出去呢),这时由于你没说过什么时候让手艺人完成,于是随便一个知道你发工具和材料这事的人,都可以向你要求提货(调用你的委托成员) ,就是我要之前你发过工具和材料的人把他的作品做完然后我看看买不买,于是你就挨着个儿地找之前找你要过工具和材料的匠人要作品,这就是委托调用,由于是同步调用,所以你(主线程)就只能一个一个找人,找到一个就要让这个收到材料和工具的匠人开始制作,等他做完,再去下一个人那儿收货,所以你得到所有作品所消耗的时间就是所有匠人做出作品的时间之和,有可能这时人家顾客已经等超时,就走了,有可能你之前发的这几个匠人做的作品都不符合他要求,但你只发了这几个人,于是你耗了时间货还压在你手里,好悲催~。
 
那么,c#事件呢?
故事继续,还是这个能发工具和材料的你,还是这个市,经历了上面挨个收作品的这个事,你觉得随便一个人都可以过来要求你中断你自己的事去要作品(执行委托),你非常不爽(其实挨个收作品很耗时间,这也让顾客很不满意,但你并没有意识到),所以,你决定不让外人有权这样要求你,于是你说了,什么时候收作品,老子自己说了算(事件对委托的内部封装),这样别人说收不管用了,然后你就把之前发工具材料的那个委托(delegate)封装成了一个事件(event),于是,收作品这个事儿就变成你自己说了算了(编译时会变成private),由于什么时候说收就收了,所以你每次能跑遍100个匠人那去要作品,或者手里有多少工具和原材料,就能发出去多少份。
所以,事件就是委托,只不过将委托封装成了内部的调用特性(至于事件怎么调用怎么定义,以及编译后变成什么代码,可以去那两篇美文里扣,我这儿只讲故事)。
应用了内部事件,由于没有人打扰你分发任务了,于是慢慢你就觉得,这么干还真是特么够慢啊……,100个人我挨着个要,这不傻一漏么?而且,别人中途找我要东西,我也顾不上理他啊,我(主线程)还在外面挨着个收东西呢,这不气跑了客人才怪。不行,我得换个套路做买卖。
 
于是,异步的概念诞生了
前思后想,我发完了以后,我告诉他们一块儿开始弄( MyEvent.GetInvocationList()),弄完我再收不得了么(beginInvoke(toolobj , meterailobj , null, null))?就算我不把工具和材料全发完了,谁领了东西谁就开始,我给他个快递电话,弄完给我递过来( )不得了(于是你养活了这里的快递行业)?这时候反正他开始了,谁来找我要我就专门等他那个干完给我(  IAsyncResult asyncResult = del.BeginInvoke(2,5,null,null); //中间是blabla.... ),做完交易EndInvoke(asyncResult); 再干我别的事儿(主线程其它程序块儿...)不就行?这时候别人也没停啊(线程池(Thread.CurrentThread.IsThreadPoolThread)),这效率多高?
 
采用这个策略之后,你把做生意的理念改了,一有材料除了往外发就是收快递,要么就是见客户,忙得好生了得。
 
干了好一阵生意,你发现你自己已经熟知了市场行情,也对艺术有了一定的鉴赏力,于是你就琢磨着怎样让这帮匠人拿回材料工具后,能按照自己的意思去弄出作品,于是你开始琢磨着每次派发工具和材料的同时再给匠人一些主题之类的信息,这样就充分利用了手头的工匠资源,能更让出活的作品符合当前市场的预期。于是你就这么干了,每次发了工具在手艺人表示可以开始干((beginInvoke(null, EventArgs.Empty, null, null) )的时候,你就来劲了,大吹一通现在的灵感(string data =http://www.mamicode.com/ "Any data you want to pass.";),多么多么希望达到一种效果这才是艺术之类的牛,然后让匠人深受感染,根据你的思想感情去创作作品,由于是按照你的意思来的,所以在做完之后,你有修改作品的权利 (AsyncCallback callBack = new AsyncCallback(OnAddComplete);),并为此塞给了一笔额外的钱给匠人。于是匠人原来的创作模式硬生生塞入了你的意思以后变成了你还能修改的作品( del.BeginInvoke(toolobj,meterailobj , callBack, data);)。
 
异步的好处
异步最大的好处,我认为就是主线程可以像故事里做生意的主人公抓人同时做事那样,抓出线程池中可用的资源及时执行(最顶上那两篇文章里面已经详细解释过是怎样的一个情景了,而且写得非常易懂,我就不画蛇添足解释了),然后执行的过程、结果以及对结果的控制,都通过beginInvoke 返回的 IAsyncResult,传入参数AsyncCallback 以及传入的数据参数,进行了很好的封装,可以使单线等待任务变为并发线程任务,很好得封装了一组线程协作的实现。
 
再来说说故事的结尾吧:
于是,匠人们跟着你的意思做事,然后做出来的东西又被你根据自己的审美修改一通,你就愈发沉迷于高效率与自我实现的快感中,由于每次都要额外付一大笔钱给匠人,而且越难的主题越贵,导致了开销大幅增长,再由于对手的竞争(都是各种胡吹各种挖墙脚),市场变化很快,并且由于你有了钱了就学坏,名声就渐渐变差,有钱人买你的东西觉得有点掉价,于是买的人也少了,投入小于产出,很快你自己的产业就败落了,由拥有更好名声更好经营习惯的商人取代了(真是皆大欢喜啊~)。

对张子扬显示的两篇委托和事件说得很透文章读后的思考