转自:http://www.csharpwin.com/csharpspace/7548r2766.shtml

在《关于最近面试的一点感想》一文中,Michael同学谈到他在面试时询问对方“delegate在.net framework1.1,2.0,3.5各可以怎么写”这个问题。于是乎,有朋友回复道“请问楼主,茴香豆的茴有几种写法”,“当代孔乙己”,独乐,众 乐。看了所有的评论,除了某些朋友认为“的确不该不知道这个问题”之外,似乎没有什么人在明确支持楼主。

不过我支持,为什么?因为我也提过出这样的问题:各版本.NET委托的写法有何不同?

这样,我们暂且不提应聘“高级开发人员”的人,在“自称熟悉各版本.NET框架”的前提下,是否应该知道这个答案。我们也暂且不提Michael同学提问的“目的”是什么。老赵就先单独针对这个问题进行解释,然后谈谈自己为什么会提出这个问题吧。

可能有一件事情需要说在前面,那就是:委托本身其实从来没有改变过,改变的一直都是委托的“写法”。因此更确切地说,改变的只是“编译器”。而本文所有内 容都用C#来实现,其实谈得也都是C#编译器本身——但是其实VB.NET也有变化埃再由于.NET版本和C#版本的关系也是非常密切的,因此全文就使 用.NET版本进行指代了。

.NET 1.x中委托的写法

委托,如果不追究细节,从表面上来看我们可以将其通俗地理解为一个安全的“函数指针”。当然,这个函数指针其实也是一个对象,有自己的成员,也会封装了被调用方的上下文等等。至于委托的定义和使用方式,则是这样的:

  1. public delegate int SomeDelegate(string arg1, bool arg2);
  2. public static int SomeMethod(string arg1, bool arg2) { return 0; }
  3. public class SomeClass
  4. {
  5. public int SomeMethod(string a1, bool a2) { return 0; }
  6. public event SomeDelegate SomeEvent;
  7. }
  8. static void Main(string[] args)
  9. {
  10. SomeClass someClass = new SomeClass();
  11. SomeDelegate someDelegate = new SomeDelegate(someClass.SomeMethod);
  12. someClass.SomeEvent += new SomeDelegate(SomeMethod);
  13. }

可见,在.NET 1.x中需要使用new DelegateType(...)的方式来创建一个委托对象。不过,作为委托对象内部的方法它既可以是实例方法,也可以是静态方法。此外,方法只需要匹配委托类型的签名和返回值即可,方法参数的名称不会成为约束。

嗯,就是这么简单。

.NET 2.0中委托的写法

.NET委托引入了范型,且写法略有简化:

  1. public delegate TResult MyFunc(T1 a1, T2 a2);
  2. public static int SomeMethod(string a1, bool a2) { return 0; }
  3. static void Main(string[] args)
  4. {
  5. MyFunc<stringboolint> myFunc = SomeMethod;
  6. }

在.NET 2.0中,new DelegateType已经可以省略,开发人员可以直接将方法赋值给一个委托对象的引用。当然,这个改进不值一提,.NET 2.0中委托写法的关键在于引入了“匿名方法”:

  1. public static void TestRequest(string url)
  2. {
  3. WebRequest request = HttpWebRequest.Create(url);
  4. request.BeginGetResponse(delegate(IAsyncResult ar)
  5. {
  6. using (WebResponse response = request.EndGetResponse(ar))
  7. {
  8. Console.WriteLine("{0}: {1}", url, response.ContentLength);
  9. }
  10. },
  11. null);
  12. }

匿名方法,简单地说就是内联在方法内部的委托对象,它的关键便在于形成了一个闭包(委托执行时所需的上下文)。如上面的代码 中,BeginGetResponse的第一个参数(委托)可以直接使用TestRequest方法的参数url,以及方法内的“局部”变量 request。如果没有匿名函数这个特性的话,代码写起来就麻烦了,例如在.NET 1.x中您可能就必须这么写:

  1. public static void TestRequest(string url)
  2. {
  3. WebRequest request = HttpWebRequest.Create(url);
  4. object[] context = new object[] { url, request };
  5. request.BeginGetResponse(TestAsyncCallback, context);
  6. }
  7. public static void TestAsyncCallback(IAsyncResult ar)
  8. {
  9. object[] context = (object[])ar.AsyncState;
  10. string url = (string)context[0];
  11. WebRequest request = (WebRequest)context[1];
  12. using (WebResponse response = request.EndGetResponse(ar))
  13. {
  14. Console.WriteLine("{0}: {1}", url, response.ContentLength);
  15. }
  16. }

此时,我们往往会发现,开发人员需要花费大量的精力,为一小部分代码维护一大段上下文。例如在这段代码中,我们会将url和request对象塞入一个 object数组中,在回调函数中再通过危险的Cast操作恢复数据。如果您希望“强类型”,那么只能为每个回调创建一个新的上下文对象,维护起来可能更 加麻烦——要知道,在并行编程,异步调用越来越重要的今天,如果没有匿名方法自动保留上下文的特性,开发人员会为这些“额外工作”疲于奔命的。

可能您会说,匿名方法的可读性不佳,因为需要“内联”。一个方法中内联太多,维护成本就上去了,所以匿名方法并不推荐使用。我想说的是,您错了。如果为了可维护性,要将方法独立拆开,也可以利用匿名方法的优势:

  1. public static void TestRequest(string url)
  2. {
  3. WebRequest request = HttpWebRequest.Create(url);
  4. request.BeginGetResponse(delegate(IAsyncResult ar)
  5. {
  6. TestAsyncCallback(ar, request, url);
  7. }, null);
  8. }
  9. public static void TestAsyncCallback(IAsyncResult ar, WebRequest request, string url)
  10. {
  11. using (WebResponse response = request.EndGetResponse(ar))
  12. {
  13. Console.WriteLine("{0}: {1}", url, response.ContentLength);
  14. }
  15. }

如果借助.NET 3.5中的Lambda表达式,代码可以写的更简单易读:

  1. public static void TestRequest(string url)
  2. {
  3. WebRequest request = HttpWebRequest.Create(url);
  4. request.BeginGetResponse(ar => TestAsyncCallback(ar, request, url), null);
  5. }

以上就总结了各版本.NET委托的写法。

各版本.NET委托的写法回顾(转)的更多相关文章

  1. webpack版本1与版本2的若干写法区别

    2.x的环境遇到类似this._init is not a function的报错. 版本1.x的写法: resolve: { extensions: ['', '.js', '.vue'] }, m ...

  2. TP5.0 controller下分版本 分块 分目录写法访问

    这个写法是在api模块下的controller目录下又分出了v1和以后未知的v(x)版本,这个时候需要配置路由来访问这个接口类似于这种形式: http://www.xx.com/index.php/a ...

  3. js事件委托 jQuery写法

    http://www.cnblogs.com/liugang-vip/p/5616484.html 不是抄的,这篇文章写的细 这是js 事件委托写法 <!DOCTYPE html> < ...

  4. 五年26个版本:Linux系统内核全程回顾

    Phoronix.com今天将他们对Linux系统的研究发挥到了极致:从2005年年中的2.6.12,到正在开发中的2.6.37,五年多来的26个Linux内核版本来了个“群英荟萃”! 完成如此庞大规 ...

  5. c# 委托 delegate

    委托是一种存储函数引用的类型,在事件和事件的处理时有重要的用途 通俗的说,委托是一个可以引用方法的类型,当创建一个委托,也就创建一个引用方法的变量,进而就可以调用那个方法,即委托可以调用它所指的方法. ...

  6. 委托、Lambda表达式和事件

    1.1 引用方法      委托是寻址方法的 .NET 版本.委托是类型安全的类.它定义了返回类型和参数的类型.委托类不仅包含对方法的引用,也可以包含对多个方法的引用.      Lambda 表达式 ...

  7. C#基础系列——委托实现简单设计模式

    前言:上一篇介绍了下多线程的相关知识:C#基础系列——多线程的常见用法详解,里面就提到了委托变量.这篇简单介绍下委托的使用.当然啦,园子里面很多介绍委托的文章都会说道:委托和事件的概念就像一道坎,过了 ...

  8. JS事件委托学习(转)

    JS 事件委托就是利用冒泡原理,把事件加到父级上触发,执行效果. 好处: 1.提高性能 2.新添加的元素还会有之前的事件     <</</</</li></ ...

  9. 针对主流浏览器的CSS-HACK写法及IE常用条件注释

    一.通用区分方式: IE6.IE7能识别*,标准浏览器(如FF)不能识别*:IE6能识别*,但不能识别 !important:IE7能识别*,也能识别 !important:IE8能识别\0,不能识别 ...

随机推荐

  1. vss登录invalid handle问题的解决办法

    VSS登录出现“invalid handle” 原因:网络验证. 解决方法: 1.打开控制面板:选择“用户帐户和家庭安全” 2.选择凭据管理器: 3.添加Windows 凭据 这一步特别重要: (1) ...

  2. sql:inner join,left join,right join,full join用法及区别

    join的语法: select [字段] from [表名1] inner/left/right/full join [表名2] on [表名1.字段1] <关系运算符> [表名2.字段2 ...

  3. 织梦文章里面的图片alt和title属性,用文章标题自动替换

    把{dede:field.body/}改成{dede:field.body runphp=yes}global $dsql,$id,$aid;$myid = isset($id) ? $id : $a ...

  4. document.write : 什么是在html输出中使用,什么是文档加载后使用?

    理解:您只能在 HTML 输出中使用 document.write.如果您在文档加载后使用该方法,会覆盖整个文档. Javascript中只能在 HTML 输出流中使用 document.write, ...

  5. ubuntu16.04安装wps

    下载: 我的电脑是64位的,所以选择64bit的deb包进行下载 1.下载地址:http://community.wps.cn/download/(去WPS官网下载) 安装: 2.执行安装命令:sud ...

  6. Cookie 和 Session 的区别和联系?session的生命周期?多个服务器部署session的管理?

    一.session 和 cookie 1.cookie Cookie会根据响应报文里的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie.当下次客户端再向服务端发起请求时,客户端会 ...

  7. MAC/Xcode简单操作命令

    快捷键: command(windows) + c: 复制 command + V : 粘贴 command + x: 剪切(只在当前应用程序内有效) 在mac系统下表示剪切功能: 先command ...

  8. PHP学习笔记(一)

    1.什么是 PHP? PHP 指 PHP:超文本预处理器(译者注:PHP: Hypertext Preprocessor,递归命名) PHP 是一种服务器端的脚本语言,类似 ASP PHP 脚本在服务 ...

  9. jzoj P1163 生日派对灯

    在IOI98的节日宴会上,我们有N(10<=N<=100)盏彩色灯,他们分别从1到N被标上号码.这些灯都连接到四个按钮:  按钮1:当按下此按钮,将改变所有的灯:本来亮着的灯就熄灭,本来是 ...

  10. Vuebnb 一个用 vue.js + Laravel 构建的全栈应用

    今年我一直在写一本新书叫全栈Vue网站开发:Vue.js,Vuex和Laravel.它会在Packt出版社在2018年初出版. 这本书是围绕着一个案例研究项目,Vuebnb,简单克隆Airbnb.在这 ...