委托的秘密
我们一直在说委托是和类一样的类型,拿不出确凿的证据你可能很难相信。委托实际上就是一个自定义的类,我们在定义了一个委托后,在编译时系统会为我们创建一个委托类,这个类的大部分构建工作由系统自动完成。要查看委托类型的秘密,我们需要以前用过的方法,就是用反编译工具查看委托到底被编译成什么。我们用ILDasm.exe来查看上面MySayDeleage委托生成的中间代码。从源代码中我们只看到Me和Program两个类,那么剩下的那个MySayDeleage类是哪里来的呢?就是我们上面定义的委托类型MySayDeleage编译后的结果。仔细观察你会发现,委托类实际上就是一个继承自MulticastDelegate基类的一个自定义类。如此一来,那么委托定义的对象实际上也和我们以前用类定义的对象本质上是一样的。至于委托如何代表其方法的执行,那是太底层的东西,我们不需要了解。其他的我们也不再深入分析了,知道委托实际上是一个类就容易理解委托定义前面的访问修饰符是什么作用了(参考类的),就明白为什么委托类型可以定义对象了。
多播委托——引发连锁反应
多播委托是委托的一种特殊应用,多播委托允许将多个委托对象组成一个委托链。关于“链”的叫法在这里也形象地表示出委托链的作用。我们经常说某个事件造成了什么连锁反应,比如说泰国的金融事件造成了整个东南亚连锁反应,从而导致东南亚各国的经济危机。委托链的作用也是这样,委托链可以承载很多方法,一旦触发该链,那么将调用链中的所有方法。创建一个多播委托和创建普通委托没什么两样,我们可以使用“+”号运算符把委托对象加入委托从而形成委托链,利用“-”运算符从委托链移除一个委托。下面我们来看一下上一节那个MySayDeleage的多播版本
代码实现:
using System;
using System.Collections.Generic;
using System.Text;
namespace MyDelegate
{
public delegate void MySayDeleage();
class Me
{
public void SayHello() { Console.WriteLine("你好,很高兴认识你"); }
public void SayLoveYou() { Console.WriteLine("我爱你"); }
public void SayBye() { Console.WriteLine("再见"); }
}
class Program
{
static void Main(string [] args)
{
Me me=new Me();
MySayDeleage mySay=new MySayDeleage(me.SayHello);
mySay+=new MySayDeleage(me.SayLoveYou);
mySay+=new MySayDeleage(me.SayBye);
mySay();
}
}
}
上面代码的运行结果和上一次一样。我们定义了一个名称为mySay的委托对象,然后我们使用三个加等于号将三个方法的委托对象分别加入到mySay委托当中,从而形成委托链。当我们使用mySay()激发该委托时,将会依次调用这三个方法。这里要注意,新的委托使用语法(C#2.0以后)可以让我们在给委托对象赋值时省略掉new关键字,这样写的话更能展现委托的本质,如上面给委托赋值的代码可以直接写成:
MySayDeleage mySay=new me.SayHello;
mySay+=me.SayLoveYou;
mySay+=me.SayBye;
不管怎么说,多播委托实际上只是委托的一种特殊用法,在使用时要注意一些问题:
(1)多播委托的委托方法最好是没有返回值的方法,也就是void方法,如果委托了带有返回值的方法也无法获得级联的结果,比如我们这样使用上面那个算术委托:
CalculateCall cal=new CalculateCall(Add);
cal+=new CalculateCall(Substract);
int result=cal(4,6);
Console.WriteLine("结果是{0}",result);
结果是“-2”,虽然调用了两个方法,但是只有最后一个方法返回了结果。
(2)多播委托只支持+、-、+=、-+四种运算。我们来看一下下面的一个例子:
delegate void Del(string s);
class TestClass
{
static void Hello(string s)
{
System.Console.WriteLine(" Hello,{0}!",s);
}
static void Goodbye(string s)
{
System.Console.WriteLine(" Goodbye,{0}!",s);
}
static void Main()
{
Del a,b,c,d;
a=Hello;
b=Goodbye;
//建立组合委托c、是a、b两个委托组成的委托链
c=a+b;
//从委托链中去除a委托
d=c-a;
System.Console.WriteLine("调用委托a:");
a("A");
System.Console.WriteLine("调用委托b:");
b("B");
System.Console.WriteLine("调用委托c:");
c("C");
System.Console.WriteLine("调用委托d:");
d("D");
}
}
结果是:
调用委托a:
Hello,A!
调用委托b:
Goodbye,B!
调用委托c:
Hello,C!
Goodbye,C!
调用委托 d:
Goodbye,D!
上面所有的例子都只是为了演示委托的用法,实际应用中的委托技术用法远远不只如此。利用委托不仅可以完成传统的函数回调机制,而且可以实现很多其他的功能