繁体中文
设为首页
加入收藏
当前位置:.Net技术首页 >> Asp.Net开发 >> 重温委托[delegate]

重温委托[delegate]

2007-09-15 08:00:00  作者:  来源:互联网  浏览次数:0  文字大小:【】【】【
简介:一) 定义: 委托声明和定义了一种引用类型,这种类型具有自己的签名并能够封装静态函数和实例的方法,一旦为委托分配了方法,委托将具有和该方法具有完全相同的行为。委托类似 C++ 的函数指针,但是委托是类型安...
关键字:委托 delegate

一) 定义:

委托声明和定义了一种引用类型,这种类型具有自己的签名并能够封装静态函数和实例的方法,一旦为委托分配了方法,委托将具有和该方法具有完全相同的行为。委托类似 C++ 的函数指针,但是委托是类型安全的。打个比方: 如果市长出差,那么他就会委派他的秘书代理他的日常事务,此时秘书就拥有了和市长的一样的权利,他就能暂时代理市长的事务。此时秘书就成了"委托类型"。

二) 原型声明:

public delegate void TestDelegate(string message);

先看下面的简单例子:

1using System;

2

3//声明了一个委托,并定义了委托的签名

4delegate void SampleDelegate(string message);

5

6public class SampleClass

7{

8 //静态方法

9 static public void SampleStaticMethod(string message)

10 {

11 Console.WriteLine(message);

12 }

13

14 //类的实例方法

15 public void SampleObjectMethod(string message)

16 {

17 Console.WriteLine(message);

18 }

19}

20

21class MainClass

22{

23 static void Main()

24 {

25 //可以将静态函数分配给委托,也可以将匿名方法分配给委托,但都必须符合委托的签名

26

27 //将静态函数分配给委托

28 SampleDelegate d1 = new SampleDelegate(SampleClass.SampleStaticMethod);

29 //将静态函数分配给委托

30 SampleDelegate d2 = SampleClass.SampleStaticMethod;

31 //将实例方法分配给委托

32 SampleClass sampleclass = new SampleClass();

33 SampleDelegate d3 = new SampleDelegate(sampleclass.SampleObjectMethod);

34 //将匿名方法分配给委托

35 SampleDelegate d4 = delegate(string message)

36 {

37 Console.WriteLine(message);

38 };

39

40 d1("d1");

41 d2("d2");

42 d3("d3");

43 d3("d4");

44

45 Console.ReadLine();

46 }

47}

输出的结果:

通过上面的例子,我们可以看到使用委托要分三步走:

1) 声明委托

delegate void SampleDelegate(string message);

2) 实例化委托

SampleDelegate d1 = new SampleDelegate(SampleClass.SampleStaticMethod);

..............

3) 回调委托

d1("d1");

...................

委托可以回调三种方法:

1) 静态方法

SampleDelegate d1 = new SampleDelegate(SampleClass.SampleStaticMethod);

2) 类的实例方法

SampleClass sampleclass = new SampleClass();

SampleDelegate d3 = new SampleDelegate(sampleclass.SampleObjectMethod);

3) 匿名方法

SampleDelegate d4 = delegate(string message)

{

Console.WriteLine(message);

};

三) 委托的原理

反编译刚才的类,我们就可以看到如下结果:

在源程序中,我们并没有定义SampleDelegate这个类,可是这却有这样一个类。 为什么呢?

这里就引出了委托的秘密。

我们之前声明的delegate void SampleDelegate(string message)这个委托,编译器为将编译成一个完整的类。这个类中继承了MulticastDelegate这个类,并且定义了三个虚方法。其中Invoke(string):void这个方法执行回调方法。

再看以下MainClass中的Main编译后生成的中间语言:

1.method private hidebysig static void Main() cil managed

2{

3 .entrypoint

4 // Code size 134 (0x86)

5 .maxstack 3

6 .locals init ([0] class SampleDelegate d1,

7 [1] class SampleDelegate d2,

8 [2] class SampleClass sampleclass,

9 [3] class SampleDelegate d3,

10 [4] class SampleDelegate d4)

11 IL_0000: nop

12 IL_0001: ldnull

13 IL_0002: ldftn void SampleClass::SampleStaticMethod(string)

14 IL_0008: newobj instance void SampleDelegate::.ctor(object,

15 native int)

16 IL_000d: stloc.0

17 IL_000e: ldnull

18 IL_000f: ldftn void SampleClass::SampleStaticMethod(string)

19 IL_0015: newobj instance void SampleDelegate::.ctor(object,

20 native int)

21 IL_001a: stloc.1

22 IL_001b: newobj instance void SampleClass::.ctor()

23 IL_0020: stloc.2

24 IL_0021: ldloc.2

25 IL_0022: ldftn instance void SampleClass::SampleObjectMethod(string)

26 IL_0028: newobj instance void SampleDelegate::.ctor(object,

27 native int)

28 IL_002d: stloc.3

29 IL_002e: ldsfld class SampleDelegate MainClass::'<>9__CachedAnonymousMethodDelegate1'

30 IL_0033: brtrue.s IL_0048

31 IL_0035: ldnull

32 IL_0036: ldftn void MainClass::'

b__0'(string)

33 IL_003c: newobj instance void SampleDelegate::.ctor(object,

34 native int)

35 IL_0041: stsfld class SampleDelegate MainClass::'<>9__CachedAnonymousMethodDelegate1'

36 IL_0046: br.s IL_0048

37 IL_0048: ldsfld class SampleDelegate MainClass::'<>9__CachedAnonymousMethodDelegate1'

38 IL_004d: stloc.s d4

39 IL_004f: ldloc.0

40 IL_0050: ldstr "d1"

41 IL_0055: callvirt instance void SampleDelegate::Invoke(string)

42 IL_005a: nop

43 IL_005b: ldloc.1

44 IL_005c: ldstr "d2"

45 IL_0061: callvirt instance void SampleDelegate::Invoke(string)

46 IL_0066: nop

47 IL_0067: ldloc.3

48 IL_0068: ldstr "d3"

49 IL_006d: callvirt instance void SampleDelegate::Invoke(string)

50 IL_0072: nop

51 IL_0073: ldloc.3

52 IL_0074: ldstr "d4"

53 IL_0079: callvirt instance void SampleDelegate::Invoke(string)

54 IL_007e: nop

55 IL_007f: call string [mscorlib]System.Console::ReadLine()

56 IL_0084: pop

57 IL_0085: ret

58} // end of method MainClass::Main

可见:

1)SampleDelegate d1 = new SampleDelegate(SampleClass.SampleStaticMethod)和SampleDelegate d2 = SampleClass.SampleStaticMethod经编译器便宜后生成完全相同的中间代码。

2)d1("d1"), d2("d2")等这些方法都会调用Invoke(string)方法。

四)委托的判等

先看下面两个语句:

Console.WriteLine(d1.Equals(d2)); //显示"True"

Console.WriteLine(d1.Equals(d3)); //显示"False"

输出是什么呢?

假如回答都是False的话,那就大错了。

委托的判等有点特殊,如果两个委托他们指向的回调目标和回调方法相同,那么结果就是"True".否则"False".

d1和d2显然都是类SampleClass的静态方法SampleStaticMethod。所以d1等于d2是毫无疑问的。

五)委托链

1using System;

2delegate void D(int x);

3class C

4{

5 public static void M1(int i) {

6 Console.WriteLine("C.M1: " + i);

7 }

8 public static void M2(int i) {

9 Console.WriteLine("C.M2: " + i);

10 }

11 public void M3(int i) {

12 Console.WriteLine("C.M3: " + i);

13 }

14}

15class Test

16{

17 static void Main() {

18 D cd1 = new D(C.M1);

19 cd1(-1); // call M1

20 Console.WriteLine();

21 D cd2 = new D(C.M2);

22 cd2(-2); // call M2

23 Console.WriteLine();

24 D cd3 = cd1 + cd2;

25 cd3(1); // call M1 then M2

26 Console.WriteLine();

27 cd3 += cd1;

28 cd3(2); // call M1, M2, then M1

29 Console.WriteLine();

30 cd3 -= cd2;

31 cd3(3);

32 Console.ReadLine();

33 }

34}输出:

一目了然,C#能用"+="和"-="来实现委托链。其实"+="重载了Delegate.Combine,"-="则重载了Delegate.Remove方法。

六) 委托在.Net中的使用场合

委托主要用于三种场合:

1) 异步回调

2) 多线程,使用委托来启动多线程时调用的一个方法

3) .Net中事件模型

责任编辑:admin
相关文章