C#2.0 委托

委托

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

但是在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中我们可以使用逆变来解决这个问题

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

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

   

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

   

   

   

匿名方法

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

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

   

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

   

闭包

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

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

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

   

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

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

   

我们需要牢記的是

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

转载于:https://www.cnblogs.com/LiangSW/p/7203843.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值