首页 > 代码库 > 使用GetInvocationList对委托链进行更多的控制

使用GetInvocationList对委托链进行更多的控制

委托链中所有项都会被调用,因为委托类型的 Invoke 方法包含了对数组中的所有项进行遍历的代码。这是一个很简单的算法。尽管这个简单的算法足以应付很多情形,但也有它的局限性。例如,除了最后一个返回值,其他所有回调方法的返回值都会被丢弃。但局限并不止于此。如果被调用的委托中有一个抛出了异常或阻塞了相当长一段时间,会出现什么情况呢?由于这个简单的算法是顺序调用链中的每一个委托,所以一个委托对象出现问题,链中后续的所有对象都调用不了啊。显然,这个算法还不够健壮性。

所以 MulticastDelegate(派生于 Delegate)类提供了一个实例方法 GetInvocationList,用于显式调用链中的每一个委托,并允许你使用需要的任何算法。

GetInvocationList 方法操作从 MulticastDelegate 派生的对象,返回包含 Delegate 引用的一个数组,其中每个引用都指向链中的一个委托对象。在内部,GetInvocationList 构造并初始化一个数组,让它的每个元素都引用链中的一个委托,然后返回对该数组的引用。如果 _invocationList 字段为null,返回的数组就只有一个元素,该元素引用链中唯一的委托,即委托实例本身。

如下代码演示:

 1 using System;
 2 using System.Text;
 3 
 4 namespace _17._5._2取得对委托链调用的更多控制
 5 {
 6     class Program
 7     {
 8         // 定义委托来查询一个组件的状态
 9         private delegate string GetStatus();
10 
11         static void Main(string[] args)
12         {
13             // 声明空委托链
14             GetStatus getStatus = null;
15 
16             // 构造3个组件,将它们的状态方法添加到委托链中
17             getStatus += new GetStatus(new Light().SwitchPosition);
18             getStatus += new GetStatus(new Fan().Speed);
19             getStatus += new GetStatus(new Speaker().Volume);
20 
21             // 显式整理好的状态报告,反映这3个组件的状态。
22             Console.WriteLine(GetComponentStatusReport(getStatus));
23 
24             Console.ReadKey();
25         }
26 
27         // 该方法查询几个组件并返回状态报告
28         private static string GetComponentStatusReport(GetStatus status)
29         {
30             // 如果委托链为空,就不进行任何操作
31             if (status == null) return null;
32 
33             // 用下面的变量来创建状态报告
34             StringBuilder report = new StringBuilder();
35 
36             // 获得一个数组,其中每个元素都是链中的委托
37             Delegate[] arrayOfDelegates = status.GetInvocationList();
38 
39             // 遍历数组中每一个委托
40             foreach (GetStatus getStatus in arrayOfDelegates)
41             {
42                 try
43                 {
44                     // 获得一个组件的状态字符串
45                     report.AppendFormat("{0}{1}{1}", getStatus(), Environment.NewLine);
46                 }
47                 catch (InvalidOperationException e)
48                 {
49                     // 在状态报告中为该组件生成一个错误记录。
50                     object component = getStatus.Target;
51 
52                     report.AppendFormat(
53                         "Failed to get status from {1}{2}{0}    Error: {3}{0}{0}",
54                         Environment.NewLine,
55                         ((component == null) ? "" : component.GetType() + "."),
56                         getStatus.Method.Name,
57                         e.Message);
58                 }
59             }
60 
61             return report.ToString();
62         }
63     }
64 
65     // 定义一个灯组件
66     internal sealed class Light
67     {
68         // 该方法返回灯的状态
69         public string SwitchPosition()
70         {
71             return "The light is off";
72         }
73     }
74 
75     // 定义一个风扇组件
76     internal sealed class Fan
77     {
78         // 该方法返回风扇组件
79         public string Speed()
80         {
81             throw new InvalidOperationException("The fan broke due to overheating");
82         }
83     }
84 
85     // 定义一个扬声器组件
86     internal sealed class Speaker
87     {
88         // 该方法返回扬声器的状态
89         public string Volume()
90         {
91             return "The volume is loud";
92         }
93     }
94 }

 

使用GetInvocationList对委托链进行更多的控制