关于委托与事件的文章,一抓一大把。那我为什么还要重复造轮子呢?-----理由很简单,别人的文章是他们理解的,而不是自己所理解的,读他们的文章时,或多或少缺少一些东西。所以在此仅记自己理解的委托与事件。
一、为什么要引入(使用委托)
委托相当于方法指针,调用委托相当于触发委托中的方法。很多书籍都以对不同人以不同语言的问候作为例子,提出将方法参数化,然后再在真正的调用者中调用该方法,从而引入了委托。每当看到这种形式的时候,我总是觉得那里不对,看了半天没弄明白。直到某天,某大牛说,委托呢,从字面去理解就好了,委托就是委托第三方去帮你办某件事情,这个地方不仅可以接受你的委托,也可以接受别人的委托,从而可以进行统一的处理。这才有所理解。在使用不少次委托之后,个人觉得引入委托是可以将方法参数化,但更多的是委托可以接受多个委托的方法(符合委托定义要求的方法),实现统一处理。(常用:类之间传递参数,例如子窗体传递参数至父窗体;委托链:同时触发多个方法)。
二、委托与接口之间的区别:
接口定义了行为规范,其行为规范可以是多个的(规定多个方法、事件、属性、索引器);委托也是一种规范,委托的方法必须是同类型返回值,同类型参数的方法,但它只能定义单个的。接口的多态与委托的多播类似。
三、为什么要引入事件
事件是定义好的委托链,它只能在类的内部定义,在类的内部进行传递给其他事件(在定义其的类的内部,它可以出现在“+=”的右边实现传递),在类的外部只能是出现在“+=”或者“-=”的左边,而单纯的委托是可以的(这里只说“+=”、“-=”、“=”三种情况,如触发、判断是否为空不算)。所以事件是实现了对委托的封装。
四、为什么一般的委托不带返回值,带返回值的如何处理不同方法的返回值
因为委托实现多播,同时包含多个方法时,简单的委托触发,最终只能得到最后调用的方法的返回值,之前的则丢失,此时返回值则没太大的意义了。
五、委托异步调用
BeginInvoke..EndInvoke...很多时候在处理较长时长的业务时,将启动线程或者使用异步的方式进行处理。
零碎的学习Demo:
事件属性
private event WarnHandler mWarn; public event WarnHandler MWarn { add { // mWarn = value; //决定事件只能绑定一个方法 mWarn += value; //事件可绑定多个方法 } remove { mWarn -= value; } }
简单调用
GreedHanlder TGreed; event GreedHanlder TGreedEvent; public void Test() { Person p1 = new Person() { Name = "Tim", Language = "English" }; Person p2 = new Person() { Name = "张三", Language = "Chinese" }; ProxyPerson proxyPerson = new ProxyPerson(); proxyPerson.MGreed += p1.Greed; proxyPerson.MGreed += p2.Greed; proxyPerson.Greeding("xx"); proxyPerson.MGreed = TGreed; //单纯的代理可以在外部类重新赋值,相当于重新定义 proxyPerson.GreedEvent += TGreedEvent; p1.EGreed = p2.EGreed; // proxyPerson.GreedEvent += p1.PGreed;//(不同通过)事件只能是本身类的事件加入到其他类的事件中,不能将其他类的事件相互添加 }
public void OnGreed(string name) { if (GreedEvent != null) { GreedEvent(name); } } /// <summary> /// 逐个调用 /// 逐个调用,可以获取不同方法的返回值,但是意义不大 /// </summary> /// <param name="name"></param> public void OnGreedInner(string name) { Delegate[] delegates = MGreed.GetInvocationList(); foreach (var item in delegates) { GreedHanlder greed = (GreedHanlder)item; if (greed != null) { greed(name); } } }
异步
public delegate IList<object> QueryHandler(string name); public class ObjBo { public event QueryHandler Query; public void Test(string name) { if (Query != null) { Query.BeginInvoke(name,new AsyncCallback(BindData),null); } } public void BindData(IAsyncResult a) { AsyncResult asyncResult = a as AsyncResult; string str = asyncResult.AsyncState.ToString(); QueryHandler query = (QueryHandler)asyncResult.AsyncDelegate; IList<object> objs= query.EndInvoke(a); } }