委托与回调的暧昧

来源:互联网 发布:fifa online3 cdk淘宝 编辑:程序博客网 时间:2024/05/16 18:27

从C++转到C#的人通常会被告知一件事情:委托相当于函数指针!这样说或许没什么错,但其实容易误导新人。应该知道的是,委托是一个对象,不是函数,也不是其他形式的存在,它就是一个对象,它只是定义的时候很像一个函数,但编译器会把它自动翻译成一个对象class,之所以用函数指针类比委托,是因为它看起来像个函数,它的主要能力就是通过一个函数展现出来的,但它能做的事情包括却不限于一个函数指针


委托中最重要的两个方法是invoke和beginInvoke,又引出了同步和异步调用的概念。Invoke很简单,是阻塞的同步调用,一种常用的使用场景就是在对象A中设置一个委托,从外部给他赋值,在需要的时候执行Invoke,用函数指针的形式实现一个回调,可以达到让对象A执行一段“计划之外”代码的目的。


说到beginInvoke,它最常见用法,是把委托当另外一个线程使用,定义好委托后直接beginInvoke(null, null),可以达到让另外一个线程去执行该委托代码的效果,这比自己去创建线程或者从线程池中启动线程去做这件事情要代码直观,还能直接使用调用作用域的局部变量,十分方便:

{   int a, b// 调用作用域的局部变量   ...   Action action = new Action(() => {       Console.WriteLine((a + b).ToString());// 可使用调用作用域的局部变量   });    action.BeginInvoke(null, null);// 等价于启用一个线程去执行相关代码}


这种用法还能玩出更多花样来,比如给委托线程传入参数,比如让调用线程等待委托线程执行结束,这些功能和最基础的线程间通信是一个理儿,只不过委托把这些东西封装得更方便使用而已,此处不再多说。


这花样中有一个地方容易让人误会,就是beginInvoke传入的两个参数(至少),一个是AsyncCallback(就是一个委托),一个是object参数,为什么又要传一个委托,本来就是委托在执行了为什么又要传入一个委托,从字面上理解它又叫做回调,这不整人么这不是?!首先要明白,此委托是可传可不传的,它的行为也完全由你来定义,它不过就是在调用委托函数执行完毕以后,再执行的一个方法而已,没什么特别的,它把自己叫回调也行,委托也罢,反正就是这么回事儿,一点也不稀奇。


接下来就要说一下回调,这个概念早已如雷贯耳,我总感觉一些基础不太好的同学喜欢那这个词来修饰自己的素养,这么多年了,有时候我觉得它很神秘,又时候又似乎很简单,今天一定要撕开它的伪装,让大家看看,它一点也不神秘,它就是我让你做一件事,你做完了告诉我一声,你告诉我的这一声就是回调了。其实这样理解也多少有些误会,你可以不告诉我,你可以只是利用一些我才知道的资源做一点事情,那你这个行为我也可以美其名曰为回调;你甚至可以和我没有任何关系,在做完我要求你做的事情以后,硬生生的用我事先传给你的委托发起一个invoke操作,但操作的内容与我完全无关,我也可以死不要脸的把这个invoke叫做回调(看,我在这里给你一个回调,我的逼格很高哦)。一定要弄清楚的是:回调这个行为(过程、函数),是发生在你的线程里,是你的线程在执行这一个过程,而不是我的,所以一定不要被回调这个字面意思误导,认为是我的线程在调用这一段代码,当然你可以用一些技术手段达到类似的目的,比如你打开一个开关变量,让我可以走到你预先留下的代码段的,或者你激活事先埋伏在我身上的委托,让我自然而然的去做委托中你算计好的事情。冤冤相报就没完没了,但真相只有一个,回调是从你的线程上开始执行的!


前面说这么多都是我们自己再玩委托,其实.NET已经把它玩得炉火纯青了,想想linq,扩展方法,什么什么表达式各种show,但用法还是上面归纳的两种:当函数指针用;当线程用
原创粉丝点击