您所在的位置: 首页>>读书频道>>设计开发>>.Net系列>>

7.3.3 多播委托

http://book.51cto.com  2008-01-29 09:52  Christian Nagel等著 李铭 译 黄静 审校  清华大学出版社  我要评论(0)

7.3.3  多播委托

前面使用的每个委托都只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显式调用这个委托。委托也可以包含多个方法。这种委托称为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void;否则,就只能得到委托调用的最后一个方法的结果。
下面的代码取自于SimpleDelegate示例。尽管其语法与以前相同,但实际上它实例化了一个多播委托Operations:

delegate void DoubleOp(double value);
//   delegate double DoubleOp(double value);   // can't do this now

class MainEntryPoint
{
static void Main()
{
DoubleOp operations = new DoubleOp(MathOperations.MultiplyByTwo);
operations += new DoubleOp(MathOperations.Square);


使用委托推断可以编写上面的代码。另外,这种方式也更容易理解:

DoubleOp operations = MathOperations.MultiplyByTwo;
operations += MathOperations.Square;
在前面的示例中,要存储对两个方法的引用,所以实例化了一个委托数组。而这里只是在一个多播委托中添加两个操作。多播委托可以识别运算符+和+=。还可以扩展上述代码中的最后两行,它们具有相同的效果:

DoubleOp operation1 = MathOperations.MultiplyByTwo;
DoubleOp operation2 = MathOperations.Square;
DoubleOp operations = operation1 + operation2;

多播委托还识别运算符–和–=,以从委托中删除方法调用。

注意:
根据后面的内容,多播委托是一个派生于System.MulticastDelegate的类,System.MulticastDelegate又派生于基类System.Delegate。System.MulticastDelegate的其他成员允许把多个方法调用链接在一起,成为一个列表。

为了说明多播委托的用法,下面把SimpleDelegate示例改写为一个新示例MulticastDelegate。现在需要把委托表示为返回void的方法,就应重写MathOperations类中的方法,让它们显示其结果,而不是返回它们:

class MathOperations
{
public static void MultiplyByTwo(double value)
{
double result = value*2;
Console.WriteLine(
"Multiplying by 2: {0} gives {1}", value, result);
}

public static void Square(double value)
{
double result = value*value;
Console.WriteLine("Squaring: {0} gives {1}", value, result);
}
}
为了适应这个改变,也必须重写ProcessAndDisplayNumber:
static void ProcessAndDisplayNumber(DoubleOp action, double valueToProcess)
{
Console.WriteLine("\nProcessAndDisplayNumber called with value = " +
valueToProcess);
action(valueToProcess);
}

下面测试多播委托,其代码如下:

static void Main()
{
DoubleOp operations = MathOperations.MultiplyByTwo;
operations += MathOperations.Square;

ProcessAndDisplayNumber(operations, 2.0);
ProcessAndDisplayNumber(operations, 7.94);
ProcessAndDisplayNumber(operations, 1.414);
Console.WriteLine();
}


现在,每次调用ProcessAndDisplayNumber时,都会显示一个信息,说明它已经被调用。然后,下面的语句会按顺序调用action委托实例中的每个方法:
   action(value);

运行这段代码,得到如下所示的结果:

MulticastDelegate

ProcessAndDisplayNumber called with value = 2
Multiplying by 2: 2 gives 4
Squaring: 2 gives 4

ProcessAndDisplayNumber called with value = 7.94
Multiplying by 2: 7.94 gives 15.88
Squaring: 7.94 gives 63.0436

ProcessAndDisplayNumber called with value = 1.414
Multiplying by 2: 1.414 gives 2.828
Squaring: 1.414 gives 1.999396


如果使用多播委托,就应注意对同一个委托调用方法链的顺序并未正式定义,因此应避免编写依赖于以特定顺序调用方法的代码。

通过一个委托调用多个方法还有一个大问题。多播委托包含一个逐个调用的委托集合。如果通过委托调用的一个方法抛出了异常,整个迭代就会停止。下面是MulticastIteration示例。其中定义了一个简单的委托DemoDelegate,它没有参数,返回void。这个委托调用方法One()和Two(),这两个方法满足委托的参数和返回类型要求。注意方法One()抛出了一个异常:

 using System;
namespace Wrox.ProCSharp.Delegates
{
public delegate void DemoDelegate();
class Program
{
static void One()
{
Console.WriteLine("One");
throw new Exception("Error in one");
}
static void Two()
{
Console.WriteLine("Two");
}

在Main()方法中,创建了委托d1,它引用方法One(),接着把Two()方法的地址添加到同一个委托中。调用d1委托,就可以调用这两个方法。异常在try/catch块中捕获:

static void Main()
{
DemoDelegate d1 = One;
d1 += Two;
try
{
d1();
}
catch (Exception)
{
Console.WriteLine("Exception caught");
}
}
}
}

委托只调用了第一个方法。第一个方法抛出了异常,所以委托的迭代会停止,不再调用Two()方法。当调用方法的顺序没有指定时,结果会有所不同。

One
Exception Caught


注意:
错误和异常详见第13章。

在这种情况下,为了避免这个问题,应手动迭代方法列表。Delegate类定义了方法GetInvocationList(),它返回一个Delegate对象数组。现在可以使用这个委托调用与委托直接相关的方法,捕获异常,并继续下一次迭代。

static void Main()
{
DemoDelegate d1 = One;
d1 += Two;
Delegate[] delegates = d1.GetInvocationList();
foreach (DemoDelegate d in delegates)
{
try
{
d();
}
catch (Exception)
{
Console.WriteLine("Exception caught");
}
}
}

修改了代码后运行应用程序,会看到在捕获了异常后,将继续迭代下一个方法。

One
Exception caught
Two


【责任编辑:雪花 TEL:(010)68476606】

回书目   上一节   下一节
上一篇: 7.3.2 BubbleSorter示例 下一篇: 7.4 事件
C#实用基础教程
专题:ASP.NET 2.0基础开发指南
.NET移动与嵌入式技术专题
.NET Framework新手入门专题
VS.NET实用开发专题
 
 验证码: (点击刷新验证码)   匿名发表
  • 野蛮生长

  • 作者:冯仑著
  • “地产界的思想家”冯仑纵横生意江湖20年来,第一次系统梳理出书。  三十年来中国民营企业从前公司时代发展到公司时代,21..
Copyright©2005-2008 51CTO.COM 版权所有