多播委托

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

可以看到,结果正确。

 

posted @ 2013-04-06 10:53  阳光小屋  阅读(142)  评论(0编辑  收藏  举报