前面的每个委托只调用一个方法,一个委托可以包含多个方法,这种委托称为多播委托。如果调用多播委托就可以连续调用多个方法。但是委托的签名的返回值必须是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 ();
}
可以看到,结果正确。