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