委托

委托是一个非常不错的设计,允许我们把方法做为参数传递,实现了开放閉放原则。在方法中我们只要有一个委托占位,调用者就可以传入符合签名的方法来做不同的操作,这也面向对象开发中多态的魅力。

但是在C#1.0的时候,委托写起来实际上是非常复杂的,首先我们要声明一个委托,然后再写一个符合委托签名的方法。再创建委托实例。然后才是调用,比如下面一个简单的例子,我要在winform程序中用户按了按键后我需要彈出一个消息

因为委托的声明已经内置了,也就是KeyPressEventHandler所以我不用去写。简单一看似乎挺简洁,但是在winForm程序中会有着大量的事件,有些事件可能处理的方式非常简单,但是我们需要去相应的写一个方法。这也是比较头疼的问题。下面我们来看如何优化这个代码

方法组

在这面我们创建了一个委托实例,在C#1.0中,要同时指定委托类型和方法(操作)也就是如下图

而在C#2.0中支持从方法组到一个兼容委托的隐式转换,也就是如果方法签名和委托声明完全相同,那么就不必再去new一个委托。这时代码就变成了

但是有些方法并不是可以进行隐式转换的,如果方法需要一个Delegate类型的参数,那么我们的方法就不适用了,比如Invoke方法。这些我们就要显示转换

协变与逆变

很多人都以为这是在4.0中才支持的,因为那时有了泛型的可变性。不过这个委托的可变性完全不同。

在winform中给我们内置很多的委托类型,比如上面用到的KeyPressEventHandler,还有MouseEventHandler,他们实际上区别不大,只是参数类型不同。第一个参数类型是KeyPressEventArgs,第二个是MouseEventArgs。

不同的事件对应不同的处理,这是没有问题的。但是我们可能会有不同的事件同样的处理这种需求。在C#1.0中很遺憾是没有办法的。而在C#2.0中我们可以使用逆变来解决这个问题

KeyPressEventArgs与MouseEventArgs都派生与EventArgs类型。实际上EventArgs的派生类有多达数百个。

我们只需要有一个具有EventAgrs类型的方法,就可以这么去做

一个返回类型为基类的委托,我们想要用子类去实例化这个委托,这在之前是不可能的。而在C#2.0中,这已经没有任何问题

匿名方法

在C#2.0中設計者也意识到了创建一个委托的步骤过于繁瑣,我们要有一个完整的方法,然后再创建委托实例进行调用,在C#2.0中则出现了匿名方法来帮助我们简化这一流程(3.0中的拉姆达则更加的方便)

下面就是一个简单的匿名方法创建委托实例的例子,拿到一个字符串然后去除两边空格打印出来

虽然我们创建的是一个委托方法,但是编译成IL后每个匿名方法都会创建一个方法,会在匿名方法所在的类生成一个方法不过方法名则是乱七八糟的,不过也不是给程序员去看的。

闭包

使用方法就会使用到变量,对于匿名方法来说,分为外部变量与局部变量。很容易理解,外部变量就是匿名方法外声明的变量,而局部变量就是匿名方法内声明的变量。

如果匿名方法没有使用任何外部变量,那么则相安无事。如果使用了外部变量,那么它就是被捕获的外部变量。在匿名方法内对该变量的操作是有效的!

为什么要说闭包,是因为匿名方法会在特成的情况下延长变量的生命周期,为什么这么说呢,大家都知道委托是方法的类型,可以把方法作为委托进行返回,如果一个方法里有一个委托实例,使用的是匿名方法并且捕获了外部变量,然后把这个委托实例进行返回。这时就形成了一个闭包

这时如果去看IL会发现创建了一个新的类去容纳i变量,这也是为什么方法结束后i变量仍然存在的原因,还有一点需要注意的,外部变量只有一个,如果多个匿名方法捕获了它,那么这些匿名方法使用的都是一个变量,局部变量则没有这个问题

循环中创建的变量,每个委托捕获到的都是不同的变量

我们需要牢記的是

  • 補获的是变量,百不是创建委托初值时它的值
  • 捕获的变量生命周期被延长,至少和捕捉它的委托一样长
  • 多个委托可以捕获同一个变量
  • 必要时创建额外的类型来保存捕获变量

C#2.0 委托的更多相关文章

  1. 委托,匿名函数和lambda表达式

    很早之前就接触到了委托,但是一直对他用的不是太多,主要是本人是菜鸟,能写的比较高级的代码确实不多,但是最近在看MSDN微软的类库的时候,发现了微软的类库好多都用到了委托,于是决定好好的研究研究,加深一 ...

  2. C#—委托分析

    1.简单委托示例 using System; using System.Collections.Generic; using System.Linq; using System.Text; names ...

  3. C# 语言规范_版本5.0 (第1章 介绍)

    1. 介绍 C#(读作“See Sharp”)是一种简洁.现代.面向对象且类型安全的编程语言.C# 起源于 C 语言家族,因此,对于 C.C++ 和 Java 程序员,可以很快熟悉这种新的语言.C# ...

  4. C#6.0语言规范(一) 介绍

    C#(发音为“See Sharp”)是一种简单,现代,面向对象,类型安全的编程语言.C#源于C语言系列,对C,C ++和Java程序员来说很熟悉.EC#International将EC#标准化为ECM ...

  5. C# Language Specification 5.0 (翻译)第一章 引言

    C#(念作 See Sharp)是一种简单.现代.面向对象并且类型安全的编程语言.C# 源于 C 语言家族,因此 C.C++ 和 Java 工程师们能迅速上手.ECMA 国际[1](ECMA Inte ...

  6. C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数

    一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...

  7. C#指南,重温基础,展望远方!(11)C#委托

    委托类型表示对具有特定参数列表和返回类型的方法的引用. 通过委托,可以将方法视为可分配给变量并可作为参数传递的实体. 委托类似于其他一些语言中的函数指针概念,但与函数指针不同的是,委托不仅面向对象,还 ...

  8. C#中委托的发展与匿名函数

    匿名函数(C# 编程指南) 匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿名函数来初始化命名委托,或传递命名委托(而不是命名委托类型)作为方法参数. 共有两种匿名函数 ...

  9. jquery2.0.3 全部源码

    /*! * Includes Sizzle.js 选择器,独立的库 * http://sizzlejs.com/ */ (function( window, undefined ) { //" ...

随机推荐

  1. Python获取当前日期和日期差计算

    在Python中获取日期和时间很简单,主要使用time和datetime包 1.获取当前时间并格式化 from dateutil import rrule from datetime import d ...

  2. Win10 安装Oracle11g2、配置PL/SQL Developer11环境

    Oracle11g2的下载地址(下载以下两个压缩包,解压后得到两个oracle目录,放到一起就得到完整的安装文件了): 1.Oracle11g2: oracle-part-1 oracle-part- ...

  3. [Ubuntu]pkg-config和ldconfig

    转载自->这里 我们知道,linux编译源码包基本步骤无非是:configure,make,make install三部曲:configure过程中可能会遇到无法找到某些头文件和动态库:原因有两 ...

  4. 思科与华为RIP配置区别

    华为配置图如下: 思科配置图如下: 配置原理一样,除了配置命令有点区别:华为进入RIP的命令为:rip 1 思科进入RIP的命令为:router rip

  5. Base64简单原理

    Base64要求把每三个8bit的字节转换为四个6bit的字节(即3*8 = 4*6 = 24) 1.例如我们有一个中文字符“中国(gb2312)”,转为十进制为:中-->54992,国--&g ...

  6. prometheus — 基于文件的服务发现

    基于文件的服务发现方式不需要依赖其他平台与第三方服务,用户只需将要新的target信息以yaml或json文件格式添加到target文件中 ,prometheus会定期从指定文件中读取target信息 ...

  7. SpringAop注解实现日志的存储

    一.介绍 1.AOP的作用 在OOP中,正是这种分散在各处且与对象核心功能无关的代码(横切代码)的存在,使得模块复用难度增加.AOP则将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封 ...

  8. Jmeter之Non HTTP response code: java.net.SocketException/Non HTTP response message: Permission denied: connect

    最近在做性能测试过程中遇到了高并发时,后台监控各项指标都很正常,但是测试结果中很多Non HTTP response code: java.net.SocketException/Non HTTP r ...

  9. mac 下SonarQube 安装与使用

    参考文件:https://www.jianshu.com/p/aa863cf30406 https://www.jianshu.com/p/b41262fca5b8 jenkins 集成Sonar: ...

  10. FCC(ES6写法) Friendly Date Ranges

    把常见的日期格式如:YYYY-MM-DD 转换成一种更易读的格式. 易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st 代替 1). 包含当前年份和相同月份的时候,makeFri ...