委托声明和定义了一种引用类型,这种类型具有自己的签名并能够封装静态函数和实例的方法,一旦为委托分配了方法,委托将具有和该方法具有完全相同的行为。委托类似 C++ 的函数指针,但是委托是类型安全的。打个比方: 如果市长出差,那么他就会委派他的秘书代理他的日常事务,此时秘书就拥有了和市长的一样的权利,他就能暂时代理市长的事务。此时秘书就成了"委托类型"。
二) 原型声明:
public delegate void TestDelegate(string message);
先看下面的简单例子:
2
3 // 声明了一个委托,并定义了委托的签名
4 delegate void SampleDelegate( string message);
5
6 public 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
21 class 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编译后生成的中间语言:
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::'<Main>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是毫无疑问的。
五)委托链
六) 委托在.NET中的使用场合
委托主要用于三种场合:
1) 异步回调
2) 多线程,使用委托来启动多线程时调用的一个方法
3) .NET中事件模型
2 delegate void D( int x);
3 class 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}
15 class 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方法。
本文详细介绍了C#中委托的概念、声明、实例化及回调过程,解释了委托的内部原理,并展示了如何利用委托创建委托链。此外,还探讨了委托在.NET框架中的应用场景,包括异步回调、多线程及事件模型。
1001

被折叠的 条评论
为什么被折叠?



