声明
本文内容来自微软 MVP solenovex 的视频教程——真会C#? - 第4章 委托、事件、Lambda表达式(完结),大致和第 1 课—— 4.1 委托(上) 对应。可在 GitHub 中查看 C# 视频教程的配套PPT
本文主要包括以下内容:
- 委托类型和委托实例
- 编写插件式的方法
- 多播委托
Delegates 委托
委托是一个对象,它知道如何调用一个方法。
委托类型和委托实例
委托类型定义了委托实例可以调用的那类方法,具体来说,委托类型定义了方法的返回类型和参数。
delegate int Transformer (int x);
static int Square (int x) { return x * x; }
// static int Square (int x) => x * x;
委托实例
把方法赋值给委托变量的时候就创建了委托实例。Transformer t = Square;
调用:int answer = t(3); // answer is 9
委托的实例其实就是调用者的委托:调用者调用委托,然后委托调用目标方法。间接的把调用者和目标方法解耦合了。
编写插件式的方法
方法是在运行时才赋值给委托变量的。
public delegate int Transformer (int x);
class Util
{
public static void Transform (int[] values, Transformer t)
{
for (int i = 0; i < values.Length; i++)
values[i] = t (values[i]);
}
}
class Test
{
static void Main()
{
int[] values = { 1, 2, 3 };
Util.Transform (values, Square); // Hook in the Square method
foreach (int i in values)
Console.Write (i + " "); // 1 4 9
}
static int Square (int x) => x * x;
}
多播委托
所有的委托实例都具有多播的能力。一个委托实例可以引用一组目标方法。
+ 和 += 操作符可以合并委托实例。
SomeDelegate d = SomeMethod1;
d += SomeMethod2;
d = d + SomeMethod2;
调用 d 就会调用 SomeMethod1 和 SomeMethod2,委托的调用顺序与它们的定义顺序一致。
- 和 -= 会把右边的委托从左边的委托里移除。d -= SomeMethod1;
委托变量使用 +
或 +=
操作符时,其操作数可以是 null
。就相当于把一个新的值赋给了委托变量。
SomeDelegate d = null;
d += SomeMethod1; // Equivalent (when d is null) to d = SomeMethod1;
对单个目标方法的委托变量使用-=
操作符时,就相当于把null
值赋给了委托变量。
委托是不可变的,使用+=
或-=
操作符时,实际上是创建了新的委托实例,并把它赋给当前的委托变量。
如果多播委托的返回类型不是void
,那么调用者从最后一个被调用的方法来接收返回值。前面的方法仍然会被调用,但是其返回值就被弃用了。
所有的委托类型都派生于 System.MulticastDelegate
,而它又派生于System.Delegate
。C# 会把作用于委托的+
,-
,+=
,-=
操作编译成使用System.Delegate
的Combine
和Remove
两个静态方法。
多播委托例子
public delegate void ProgressReporter (int percentComplete);
public class Util
{
public static void HardWork (ProgressReporter p)
{
for (int i = 0; i < 10; i++)
{
p (i * 10); // Invoke delegate
System.Threading.Thread.Sleep (100); // Simulate hard work
}
}
}
class Test
{
static void Main()
{
ProgressReporter p = WriteProgressToConsole;
p += WriteProgressToFile;
Util.HardWork (p);
}
static void WriteProgressToConsole(intpercentComplete)=>Console.WriteLine (percentComplete);
static void WriteProgressToFile (int percentComplete)=>System.IO.File.WriteAllText ("progress.txt",
percentComplete.ToString());
}

参考
Delegates (C# Programming Guide)
Delegate Class
MulticastDelegate Class
网友评论