Delegate是什么

  C#中的Delegate(委托)是一种获取具有特定参数列表和返回类型的方法引用的机制,类似于C++中的函数指针。需要注意的是,和C++的函数指针不同,C#提供的Delegate完全面向对象,在我们使用Delegate之前,需要先实例化一个Delagate对象来接受方法的委托并保存该方法的引用,而不是像C++函数指针那样直接指向函数的入口地址。尽管C#提供的System.Delegate类是封装的(sealed),不能派生出其他自定义类,但我们可以声明不同的Delegate类型。在C#中,Delegate类型声明委托使用的名称确定。

Delegate的使用

  • Delegate的声明:

      C#使用关键字delegate来声明Delegate,具体语法是<access modifier> delegate <return type> <delegate-name>(<parameter list>)。以下示例声明了一个名为Del的Delegate

    1
    public delegate void Del(string message);
  • Delegate的使用:

      前面提到,Delegate表示对具有特定参数列表和返回类型的方法引用,其类型由声明委托时使用的名称确定。也就是说,当我们声明了一个Delegate之后,我们就可以使用我们声明的Delegate的名称去接受其他方法的委托。此外,我们在声明Delegate时使用的<return type>(返回类型)<parameter list>(参数列表)决定了该Delegate能接受哪些类型的函数的委托。
      这里需要注意的一点是,在C#中,当我们使用Method Loading(方法重载)时,Method Signatures(方法签名)不包括方法的返回类型。而当我们在使用Delegate时,Method Signatures(方法签名)包括方法的返回类型。换句话说,一个Delegate类型只能接受拥有相同返回类型相同参数列表的方法的委托,这就是Delegate表示对具有特定参数列表和返回类型的方法的引用的意思。

    • 首先定义几个测试的方法

      用于测试的方法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public static void DelegateMethod(string message) {
      Console.WriteLine(message);
      }

      public static void WrongMethod1(int id) {

      }

      public static string WrongMethod2(string message) {
      return message;
      }
    • 因为我们在前面声明了委托类型Del,因此我们后面可以直接将Del来声明Del类型的Delegate对象,这就是Delegate其类型由声明委托时使用的名称确定的意思。需要注意的是,在使用Delegate之前,我们需要创建Del对象。C#提供了两种方式来创建Delegate对象:使用new关键字手动创建、由程序调用System.Delegate默认构造函数自动创建。

      接受方法委托
      1
      2
      3
      4
      5
      6
      //Del handler = new Del(DelegateMethod);  //方法一
      Del handler = DelegateMethod; //方法二
      handler("Hello World");

      handler = WrongMethod1; //报错,参数列表不匹配
      handler = WrongMethod2; //报错,返回类型不匹配
    • 我们还可以将Delega对象作为参数传递给方法

      1
      2
      3
      4
      5
      public static void MethodWithCallback(int param1, int param2, Del callback) {
      callback("The number is: " + (param1 + param2).ToString());
      }

      MethodWithCallback(1, 2, handler);
  • 多播委托

      在C#中,一个Delegate对象可以接受多个方法的委托,这称为多播委托(Multicast delegates)。我们可以使用+或者+=给一个Delegate对象添加新的方法委托,也可以使用--=从一个Delegate对象上移除某个方法的委托。当一个拥有多个方法委托的Delegate对象被调用时,将按照添加的顺序进行调用

    • 定义测试的方法和委托类型

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      public delegate void RefDel(ref string message);

      public static void Method1(ref string message) {
      message += 1.ToString();
      Console.WriteLine("Method1 print: " + message);
      }

      public static void Method2(ref string message) {
      message += 2.ToString();
      Console.WriteLine("Method2 print: " + message);
      }

      public static void Method3(ref string message) {
      message += 3.ToString();
      Console.WriteLine("Method3 print: " + message);
      }
    • 创建Delegate对象并添加多个方法的委托

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      RefDel refHandler = new RefDel(Method1);
      refHandler += Method2;
      refHandler = refHandler + Method3;

      string str = "Hello Delegate";
      refHandler(ref str);

      /**********output************
      Method1 print: Hello Delegate1
      Method2 print: Hello Delegate12
      Method3 print: Hello Delegate123
      ****************************/
    • 删除方法委托

      1
      2
      3
      4
      5
      6
      7
      refHandler -= Method2;
      refHandler(ref str);

      /**********output************
      Method1 print: Hello Delegate1231
      Method3 print: Hello Delegate12313
      ****************************/

完整示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate {
class Program {
public delegate void Del(string message);
public delegate void RefDel(ref string message);

public static void DelegateMethod(string message) {
Console.WriteLine(message);
}

public static void WrongMethod1(int id) {

}

public static string WrongMethod2(string message) {
return message;
}

public static void MethodWithCallback(int param1, int param2, Del callback) {
callback("The number is: " + (param1 + param2).ToString());
}

public static void Method1(ref string message) {
message += 1.ToString();
Console.WriteLine("Method1 print: " + message);
}

public static void Method2(ref string message) {
message += 2.ToString();
Console.WriteLine("Method2 print: " + message);
}

public static void Method3(ref string message) {
message += 3.ToString();
Console.WriteLine("Method3 print: " + message);
}

static void Main(string[] args) {

Del handler = DelegateMethod;
handler("Hello World");

MethodWithCallback(1, 2, handler);

RefDel refHandler = new RefDel(Method1);
refHandler += Method2;
refHandler = refHandler + Method3;

string str = "Hello Delegate";
refHandler(ref str);

refHandler -= Method2;
refHandler(ref str);

Console.ReadLine();
}
}
}

参考链接

使用委托(C#编程指南)