CLR via C# 委托 用委托回调多个方法(委托链)
委托链是委托对象的集合。可利用委托链调用集合中的委托所代表的全部方法。
构造了三个委托对象并让fb1,fb2和fb3分别引用每个对象。
指向Feedback委托对象的引用变量fbChain旨在引用委托链(或者说委托对象集合),这些对象包装了可回调的方法。fbChain初始化为null,表明目前要回调的方法。使用Delegate类的公共静态方法Combine将委托添加到链中:
1.Combine方法发现视图合并的是null和fb1。在内部,Combine直接返回fb1的值,所以fbChain变量现在引用fb1变量所引用的委托对象。
2.Combine方法发现fbChain已引用了一个委托对象,所以Combine会构造一个新的委托对象。新委托对象对它的私有字段_target和_methodPtr进行初始化,具体的值对于目前的讨论来说并不重要。重要的是,_invocationList字段被初始化为引用一个委托对象数组。数组的第一个元素(索引0)被初始化为引用包装了StaticFeedbackToConsole方法的委托(也就是fbChain目前引用的委托)。数组的第二个元素(索引1)被初始化为引用包装了FeedbackToMsgBox方法的委托(也就是fb2引用的委托)。最后,fbChain被设为引用新建的委托对象。
3.Combine方法发现fbChain已引用了一个委托对象,因而又构造一个新的委托对象。和前面一样,新委托对象对私有字段_target和_methodPtr进行初始化,具体的值就目前来说不重要。_invocationList字段被初始化为引用一个委托对象数组。该数组的第一个元素和第二个元素(索引0和1)被初始化为引用fb1和fb2所引用的委托。数组的第三个元素(索引2)被初始化为引用包装了InstanceFeedbackToConsole方法的委托(这是fb3所引用的委托)。最后,fbChain被设为引用这个新建的委托对象。注意,之前新建的委托及其_invocationList字段引用的数组现在可以进行垃圾回收。
在fbChain引用的委托上调用Invoke时,该委托发现私有字段_invocationList不为null,所以会执行一个循环来遍历数组中的所有元素,并依次调用每个委托包装的方法。
还可以调用Delegate.Remove从链中删除委托。
Delegate.Remove方法被调用时,它扫描第一个实参(本例是fbChain)所引用的那个委托对象内部维护的委托数组(从末尾向索引0扫描)。Remove查找的是其_target和_methodPtr字段与第二个实参(本例是新建的Feedback委托)中的字段匹配的委托。如果找到匹配的委托,并且(在删除之后)数组中只剩余一个数据项,就返回那个数据项。如果找到匹配的委托,并且数组中还剩余多个数据项,就新建一个委托对象---其中创建并初始化的_invocationList数组将引用原始数组中的所有数据项,当然被删除的数据项除外---并返回对这个新建委托对象的引用。如果从链中删除了仅有的一个元素,Remove会返回null。注意每次Remove方法调用只能从链中删除一个委托,它不会删除有匹配的target和_methodPtr字段的所有委托。
前面展示的委托类型Feedback的返回值都是void。但是也可以定义:
如果是委托链,循环完成后,结果变量只包含调用的最后一个委托的结果(前面的返回值会被丢弃),该值返回给调用Invoke的代码。
//--C#对委托链的支持
为了方便C#开发人员,C#编译器自动为委托类型的实例重载了+=和-=操作符。这些操作符分别调用Delegate.Combine和Delegate.Remove。可用这些操作符简化委托链的构造。
//--取得对委托链调用的更多控制
我们已理解了如何创建委托对象链,以及如何调用链中的所有对象。链中的所有项都会被调用,因为委托类型的Invoke方法包含了对数组的所有项进行遍历的代码。这是一个很简单的算法。尽管这个简单的算法足以应付很多情形,但也有它的局限性。例如,除了最后一个返回值,其他所有回调方法的返回值都会被丢弃。但局限并不止于此。如果被调用的委托中有一个抛出了异常或阻塞了相当长一段时间,会怎样?由于这个简单的算法是顺序调用链中的每一个委托,所以一个委托对象出现问题,链中后续的所有对象都调用不了。显然这个算法还不够健壮。
由于这个算法有时候不胜其任,所以MulticastDelegate类提供了一个实例方法GetInvocationList,用于显式调用链中的每一个委托,并允许你使用需要的任何算法:
GetInvocationList方法操作从MulticastDelegate派生的对象,返回包含Delegate引用的一个数组,其中每个引用都指向链中的一个委托对象。