小尹的博客

Hi, nice to meet you.

  1. 1. 什么是委托
  2. 2. 委托定义与使用
  3. 3. 委托的使用场景
  4. 4. 多播委托
  5. 5. 强类型委托

什么是委托

委托是C#中非常重要的语法,[1]比如实现事件时,C#通过委托为事件的处理提供了语言级别的支持,而Java则不同,事件订阅者通常需要在Java中实现包含一个回调方法的Listener接口。

现实生活中的委托很好理解,举一个经典例子,[2]法庭上律师为当事人进行辩护,律师真正执行的是当事人的陈词,律师就是一个委托对象,当事人则委托律师进行辩护。

在实际应用中,需要用到委托的场景,官方文档给出了一个案例,在天文学应用程序中,对恒星进行排序时,既可以根据恒星与地球的距离排序,也可以根据恒星的大小或感知到的亮度来对他们排序。在这些排序条件下,sort()方法本质上执行的是同一种操作:基于某种比较方法,对列表中的项目进行排序。但对于每种排序顺序的代码是不同的。

也就是说,sort()方法应当在程序运行时,根据具体的对象类型进行绑定,这种绑定叫做后期绑定

C#中的委托使得函数可以作为参数被传递,作用相当于C/C++中的函数指针,以及JavaScript中的闭包

委托定义与使用

(1). 委托的定义:

1
public delegate int MyDelegate(int para1, int para2);

委托的语法可能看起来像是声明变量,但它实际上是声明类型,因为委托本质是一个类。

(2). 声明委托实例

1
2
3
4
5
6
7
8
9
10
static void Main(string[] args)
{
//声明并实例化委托变量,静态方法和实例方法均可以传递
var myDelegate = new MyDelegate(Max);
}

static int Max(int integer1, int integer2)
{
return integer1 > integer2 ? integer1 : integer2;
}

传递给委托的方法,参数个数、类型、顺序以及方法返回值,必须同委托一致。

(3). 调用委托

1
2
3
4
5
6
7
8
9
10
11
12
13
static void Main(string[] args)
{
//声明并实例化委托变量,静态方法和实例方法均可以传递
var myDelegate = new MyDelegate(Max);
//将委托传递给一个方法
ConsoleMax(myDelegate);
}

static void ConsoleMax(MyDelegate myDelegate)
{
int max = myDelegate(111, 1111);
Console.WriteLine("The max integer is {0}", max);
}

Max()通过委托的包装,作为了ConsoleMax()的参数,ConsoleMax()中调用委托myDelegate时,实际上调用的时Max()。

委托的使用场景

下面的代码块是一个经典的委托的使用场景,根据不同语言,打印不同的打招呼问候语;同时也展示了委托的隐式调用和显式调用。

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
class Program 
{
/// <summary>
/// 声明打招呼的委托类型
/// </summary>
public delegate void GreeingDelegate(string name);

static void Main(string[] args)
{
Program p = new Program();
p.Greeting("周杰伦", p.GreetingCh);
p.Greeting("Jay", p.GreetingEn);
}

/// <summary>
/// 通用打招呼方法
/// </summary>
public void Greeting(string name, GreeingDelegate callback)
{
//隐式调用委托
callback(name);
//显式调用委托
callback.Invoke(name);
}
/// <summary>
/// 英文打招呼方法
/// </summary>
public void GreetingCh(string name)
{
Console.WriteLine("你好,{0}!", name);
}

/// <summary>
/// 中文打招呼方法
/// </summary>
public void GreetingEn(string name)
{
Console.WriteLine("Hello, {0}!", name);
}
}

输出结果

你好,周杰伦!
你好,周杰伦!
Hello, Jay!
Hello, Jay!

多播委托

多播委托即多路广播委托,包装多个方法的委托,也被称为委托链。

使用”+=”操作符来链接多个方法/委托,使用”-=”操作符来移除方法/委托,下面代码块展示了其用法。

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
class Program 
{
public delegate void MyMulticastDelegate();

static void Main(string[] args)
{
MyMulticastDelegate md = null;
md += fun1;
md += fun2;
md();
Console.WriteLine("");
md -= fun2;
md();
Console.WriteLine("");
MyMulticastDelegate d1 = fun1;
MyMulticastDelegate d2 = fun2;
md += d1;
md += d2;
md();
}

public static void fun1()
{
Console.WriteLine("I'm first function");
}

public static void fun2()
{
Console.WriteLine("I'm second function");
}
}

输出结果

I’m first function
I’m second function

I’m first function

I’m first function
I’m first function
I’m second function

  • 委托方法的调用顺序和它们被添加的顺序是一致的
  • 委托是不可变的,所以+=/-=实际上是创建了新的委托
  • 若多播委托有非void的返回值,那么调用者会获取到最后一个被调方法的返回值

强类型委托

1
2
3
4
public delegate void Action();
public delegate TResult Func<out TResult>();

// Todo
本文最后更新于 天前,文中所描述的信息可能已发生改变