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

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

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

如下代码演示:

 using System;
using System.Text; namespace _17._5._2取得对委托链调用的更多控制
{
class Program
{
// 定义委托来查询一个组件的状态
private delegate string GetStatus(); static void Main(string[] args)
{
// 声明空委托链
GetStatus getStatus = null; // 构造3个组件,将它们的状态方法添加到委托链中
getStatus += new GetStatus(new Light().SwitchPosition);
getStatus += new GetStatus(new Fan().Speed);
getStatus += new GetStatus(new Speaker().Volume); // 显式整理好的状态报告,反映这3个组件的状态。
Console.WriteLine(GetComponentStatusReport(getStatus)); Console.ReadKey();
} // 该方法查询几个组件并返回状态报告
private static string GetComponentStatusReport(GetStatus status)
{
// 如果委托链为空,就不进行任何操作
if (status == null) return null; // 用下面的变量来创建状态报告
StringBuilder report = new StringBuilder(); // 获得一个数组,其中每个元素都是链中的委托
Delegate[] arrayOfDelegates = status.GetInvocationList(); // 遍历数组中每一个委托
foreach (GetStatus getStatus in arrayOfDelegates)
{
try
{
// 获得一个组件的状态字符串
report.AppendFormat("{0}{1}{1}", getStatus(), Environment.NewLine);
}
catch (InvalidOperationException e)
{
// 在状态报告中为该组件生成一个错误记录。
object component = getStatus.Target; report.AppendFormat(
"Failed to get status from {1}{2}{0} Error: {3}{0}{0}",
Environment.NewLine,
((component == null) ? "" : component.GetType() + "."),
getStatus.Method.Name,
e.Message);
}
} return report.ToString();
}
} // 定义一个灯组件
internal sealed class Light
{
// 该方法返回灯的状态
public string SwitchPosition()
{
return "The light is off";
}
} // 定义一个风扇组件
internal sealed class Fan
{
// 该方法返回风扇组件
public string Speed()
{
throw new InvalidOperationException("The fan broke due to overheating");
}
} // 定义一个扬声器组件
internal sealed class Speaker
{
// 该方法返回扬声器的状态
public string Volume()
{
return "The volume is loud";
}
}
}

最新文章

  1. JS中的函数声明错误
  2. JavaScript的面向对象编程(OOP)(三)——聚合
  3. JSP自定义标签之Hello Costom tag小例子
  4. vim下编写html的超级利器emmet
  5. jQuery 文档操作之prepend() 和prependTo()方法.
  6. 尝试Java,从入门到Kotlin(上)
  7. ubuntu16.04设置tomcat自启动
  8. JavaScript中的栈和堆内存,作用域
  9. 消息确认机制---confirm异步
  10. 20 go单元测试
  11. Jenkins卸载方法(Windows/Linux/MacOS)
  12. Process Explore & Windbg
  13. Java与SQL Server, MySql, Oracle, Access的连接方法以及一些异常解决
  14. IDEA 启动项目,tomcat中配置的虚拟路径无法使用
  15. protobuf手册
  16. wpf 转型 android开发总结
  17. ASP.NET WebApi通过自定义ControllerSelector来自定义Controller的选择
  18. 使用canvas来绘制折线图
  19. hdu-2544-最短路(SPFA模板)
  20. IOS 添加定时器(NSTimer)

热门文章

  1. Xilinx FPGA的专用时钟引脚及时钟资源相关
  2. Django - 模版语言循环字典
  3. jQuery匹配id 批量修改css属性
  4. OSI 7层模型和 TCP/IP 5层模型
  5. Flask - 路由系统
  6. qwb与学姐
  7. U - Palindrome Manacher
  8. iOS:解决pod的Insecure world writable dir问题
  9. Android自己定义Toast
  10. c# POST和GET方式通过server地址提交数据