C# CLR VIA--委托
CLR VIA
委托
所有委托类型都派生自MulticastDelegate(间接继承Delegate),其中三个重要的非公共分为别_target、_methodPtr、_invocationList,其在CLR中都有具体解释
所有委托都有一个构造器,它获取两个参数:一个是对象引用,另一个是引用了回调方法的整数,在Invoke被调用时,它使用私有字段_target和_methodPtr在指定对象上调用包装好的回调方法
所有的委托对象都是一个包装器,其中包装了一个方法和调用该方法时需要操作的对象,包装器之间通过_invocationList之间进行连接,作为委托链来使用。
对于+=和-=进行了封装,通过IL代码可以看到+=其实是调用了Delegate.Combine,而-=其实是调用了Delegate.Remove
Combine:以Combine(fbChain,fb1)为例子
- 若发现fbChain已引用了一个委托对象,会构造一个新的委托对象,对其_target和_methodPtr进行初始化,同时将_invocationList初始化为一个数组,数组中对应元素会指向对应的委托fb1(类似深度拷贝)
- 若发现是null,则直接赋予fb1中的值,fbChain变为fb1的引用
- 对于多播委托的添加(若fb1为多播委托),则会将fb1的_invocationList中的所有委托顺序加入到fbChain中,如果超过_invocationList中的length则会进行扩容操作
放上对应的部分源码:
下方是CLR中对应截图
Remove:以Remove(fbChain,fb1)为例子
其扫描第一个实参(例子中为fbChain)所引用的委托数组(从末尾向索引0扫描),Remove查找的是_target和_methodPtr字段与第二个实参(fb1)中字段相同的委托- 如果找到匹配的委托,并且数组中只剩余一个数据项,就返回该数据项
- 如果找到匹配的委托,并且数组中还剩余多个数据项,就新建一个委托对象,初始化_invocationList数组并将除删除数据外的委托放入其中,并返回引用。如果从链中删除了仅有的一个元素,Remove会返回null
- 对于多播委托的移除,会在当前索引处顺序判断是否存在某个部分与该多播委托相同,相同则进行移除
放上对应的源码:
PS:每次Remove只能从链中删除一个委托,它不会删除匹配target和_methodPtr字段的所有委托
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 风之歌!
评论