什么是委托
委托是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 { public delegate void GreeingDelegate(string name);
static void Main(string[] args) { Program p = new Program(); p.Greeting("周杰伦", p.GreetingCh); p.Greeting("Jay", p.GreetingEn); } public void Greeting(string name, GreeingDelegate callback) { callback(name); callback.Invoke(name); } public void GreetingCh(string name) { Console.WriteLine("你好,{0}!", name); } 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>();
|