多播委托
前面的每个委托只调用一个方法,一个委托可以包含多个方法,这种委托称为多播委托。如果调用多播委托就可以连续调用多个方法。但是委托的签名的返回值必须是void,否则只能够得到委托调用的最后一个方法的结果。看下面代码 // 多播委托 delegate void DoubleOp (double value ); class MathOperations { public static void MultiplyByTwo (double value ) { double result = value * 2 ; Console . WriteLine ("{0} Multiply by two = {1}" , value , result ); } public static void Square (double value ) { double result = value * value ; Console . WriteLine ("{0} squrared is {1}" , value , result ); } static void ProccessAndDisplayNumber (DoubleOp action , double valueToProccess ) { Console . WriteLine (); Console . WriteLine ("ProccessAndDisplay called with value = {0}" , valueToProccess ); // 委托会调用相应的方法 action (valueToProccess ); } // 主函数入口 static void Main () { DoubleOp operations = MathOperations . MultiplyByTwo ; operations += MathOperations . Square ; ProccessAndDisplayNumber (operations , 2.0 ); ProccessAndDisplayNumber (operations , 6.51 ); Console . ReadKey (); } } 从上面代码看到,声明了一个委托 DoubleOp , 并为他指定了两个方法,多播委托会分别连续调用两个方法,并完成对应的操作,输出结果。函数 ProccessAndDisplayNumber 中传递的第一个参数是一个委托类型,因为委托类型与对应的方法有相同的参数和返回值,因此实际传输的是方法,这就是委托的灵活性的体现 。 使用多播委托时要注意,因为委托调用方法链的顺序并没有正式定义,因此应避免编写依赖于的顶顺序调用方法的代码。还有一个很大的问题需要注意,多播委托包含一个逐个调用的委托的集合。如果通过委托调用的一个方法抛出异常,整个迭代就会停止,看下面示例: public delegate void Demo (); class Program { public static void One () { Console . WriteLine ("One" ); throw new Exception ("Error in One!" ); } static void Two () { Console . WriteLine ("Two" ); } static void Three () { Console . WriteLine ("Three" ); } static void Main () { Demo d = One ; d += Two ; d += Three ; try { d (); } catch (Exception ) { Console . WriteLine ("Exception Caught!!!" ); } Console . ReadKey (); } } 运行一下,可以看到,执行到 One() 就结束了,原因在于这个方法抛出了异常,虽然程序捕获了异常,但是委托的迭代也会就此停止。如果想要避免这个问题,就要手动迭代方法类表,使用delegate类定义的GetInvocationList(),他返回一个 delegate对象数组。因此我们把主函数改写为下: static void Main () { Demo d = One ; d += Two ; d += Three ; // 使用多播委托d的GetInvocationList方法返回广播委托的调用列表 Delegate [] delegates = d . GetInvocationList (); foreach (Demo d1 in delegates ) { try { d1 (); } catch (Exception ) { Console . WriteLine ("Exception Caught!!!" ); } } Console . ReadKey (); } 可以看到,结果正确。