C#---delegate关键字

一个委托可以绑定多个方法,使用"+="就可以向委托中添加新的方法,使用"-="可以从委托中删除方法:

如果我们从委托中减去一个它根本未添加过的方法,会怎么样呢?答案是不会报错,也不会有任何影响

还有更加现实的问题,就是如果添加的方法中有多个方法都有返回值,那怎么办?只返回最后一个具有返回值的方法的返回值

 

委托的工作原理

我们先来个委托类型的声明:

public delegate void Show();

就是这样简单的一句声明,在编译器那边可是一个大事件:

public class Show : System.MulticastDelegate
{
   //构造器
   public Show(Object object, IntPtr method);
   //与声明一样的方法
   public virtual void Invoke();
    ....
}

      编译器会生成一个与委托同名的类,该类有四个方法,这里只关注前两个,剩下两个方法涉及到异步调用,暂且不谈。
      所有的委托都有构造器,该构造器接受两个参数:对象引用object和方法标识值method(整数)。对象引用其实就是this引用,而方法标识值是一个特殊的整数,它标识了我们想要回调的方法,它是从MethodDef或MemberRef元数据token获得,至于这两个东西到底是什么,这里不展开,因为我只是初学者,最好不要一开始就纠缠于编译器实现的内容。对于静态方法,object为null,因为静态方法没有this引用。

      这两个值是理解委托工作原理最重要的部分。

      我们先看看它们保存在哪里。在编译器生成的类中,有三个继承自MulticastDelegate的私有字段:

      _target: 对象引用;

      _methodPtr:标识要回调的方法的整数值;

      _invocationList:构造方法组时,引用一个委托数组。

      _invocationList这个字段非常特殊,一般都是null,但如果我们为委托添加一个方法组(method group, 有些地方称为委托链),该字段就会引用一个委托数组。在我们使用"+="为委托添加方法的时候,其实就是添加方法组。什么叫方法组呢?就是能够被委托实例包装的方法,它们的特点就是匹配委托声明的签名和返回值。当我们添加方法组的时候,编译器其实都在为我们添加的每一个方法生成一个委托,然后将该委托和前一个委托放进一个数组中,该数组的大小刚刚好能够容纳这两个委托。就是因为这样,使得每次添加新的方法(委托)时,编译器都必须重新创建一个新的数组来容纳新的委托,然后将之前的委托和数组都交给垃圾回收器回收。其实从_invocationList中的List就可以知道它的低层是怎样实现的。学过java的人一定对容器类List非常熟悉,它的工作原理也是同样的道理:低层是一个数组,当该数组无法容纳新的元素时,就会自动将数组大小扩为两倍。

     从方法组中删除方法也是同样的过程,如果方法组中还有超过一个非null的元素,就会生成一个新的数组来容纳剩下的元素。但删除方法只能一次删除一个,而不是删除所有匹配的方法,事实上方法组中的所有方法都是匹配的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值