delegate是C#中的关键字,它的作用是啥,去网上搜会出现一堆晦涩难懂的描述,看的人头疼。本人初学C#,懂C语言,搞懂delegate之后我发现它不就是个函数指针吗!!!

C语言的函数指针

  先看看C语言里的函数指针是怎么用的,如果我们想定义一个具有一个int类型返回值,并且有两个int类型的参数的函数指针,我们会这样写:

typedef int (*func)(int, int);

  这时可以用func去定义函数指针,举例:

 1 #include <stdio.h>
 2 
 3 typedef int (*func)(int, int);
 4 
 5 int add(int a, int b)
 6 {
 7     return a + b;
 8 }
 9 
10 int main(int argc, const char *argv[])
11 {
12     func p;
13 
14     p = add;
15 
16     printf("p(3, 4) = %d\n", p(3, 4));
17     return 0;
18 }

执行结果:

 

 

 C#中的delegate

  C#中用delegate声明一个委托,用法如下:

delegate int Method(int a1, int a2);

  其实这一句和C语言中的 typedef int (*func)(int, int); 作用如出一辙,写了这一句之后就可以用Method去定义一个类似于C语言函数指针的东西。测试代码如下:

 1 using System;
 2 
 3 namespace Test
 4 {
 5     class Test
 6     {
 7         delegate int Method(int a1, int a2);
 8 
 9         static int add(int a, int b)
10         {
11             return a + b;
12         }
13 
14         static void Main(string[] args)
15         {
16             Method p;
17 
18             p = add;
19 
20             Console.WriteLine("p(3, 4) = {0}", p(3, 4));
21             Console.ReadKey();
22         }
23     }
24 }

执行结果:

 

 

 它也可以和C语言的函数指针一样,用不同的函数指针去赋值,测试代码如下:

 1 using System;
 2 
 3 namespace Test
 4 {
 5     class Test
 6     {
 7         delegate int Method(int a1, int a2);
 8 
 9         static int add(int a, int b)
10         {
11             return a + b;
12         }
13 
14         static int sub(int a, int b)
15         {
16             return a - b;
17         }
18 
19         static void Main(string[] args)
20         {
21             Method p;
22 
23             p = add;
24             Console.WriteLine("p(3, 4) = {0}", p(3, 4));
25             p = sub;
26             Console.WriteLine("p(3, 4) = {0}", p(3, 4));
27 
28             Console.ReadKey();
29         }
30     }
31 }

执行结果:

 

 

 可以用new去给Method定义的变量赋值,也可以赋值为null,比如下面两句这样写是可以的,如果赋值为null,它就相当于C语言里的空指针,是不能拿去调用的。

Method p = new Method(add);
Method q = null;

delegate多播

  delegate还有和C语言不一样的地方,如下面这个程序:

 1 using System;
 2 
 3 namespace Test
 4 {
 5     class Test
 6     {
 7         delegate int Method(int a1, int a2);
 8 
 9         static int add(int a, int b)
10         {
11             Console.WriteLine($"add({a}, {b}) = {a+b}");
12             return a + b;
13         }
14 
15         static int sub(int a, int b)
16         {
17             Console.WriteLine($"sub({a}, {b}) = {a-b}");
18             return a - b;
19         }
20 
21         static void Main(string[] args)
22         {
23             Method p = add;
24             p += sub;
25 
26             Console.WriteLine("p(3, 4) = {0}", p(3, 4));
27 
28             Console.ReadKey();
29         }
30     }
31 }

  如果用C语言的思维去看第23行和第24行,在第23行已经给p赋值为add了,然后在第24行让它加上sub是什么意思,两个函数指针能相加吗?第26行代码的输出结果又会是什么呢?看看程序的执行结果吧:

 

 

   结果表明,p先执行了add,再执行了sub,p的返回值是sub的返回值。这种用法其实是将方法加到队列之后,委托的执行过程与加入队列的顺序一致,委托执行的返回值是最后一个加入队列的方法的返回值。甚至这样写都没问题:

Method p = add;
p += sub;
p += add;
p += sub;
Console.WriteLine("p(3, 4) = {0}", p(3, 4));

执行结果如下:

 

 

 委托不但可以加,还可以减,如果队列里没有要减去的方法,那就不会减了,比如下面这种写法:

Method p = add;
p -= sub;
Console.WriteLine("p(3, 4) = {0}", p(3, 4));

p里面只有add,若要让它减去sub那肯定是减不了的,不过程序执行并不会出错,最后的运行结果是只运行add。

那委托中减的顺序是怎样的呢?看下面这段代码:

1 Method p = add;
2 p += sub;
3 p += add;
4 p += sub;
5 
6 p -= sub;
7 Console.WriteLine("p(3, 4) = {0}", p(3, 4));

执行结果:

 

 

 如果将上面代码块第6行的sub换成add,那么执行结果是:

 

 

 这两个例子表明,委托中减的顺序是从队列的最后面开始的。