委托
委托的定义
- 委托是一个自定义数据类型。所以通常定义在
namespace
里。 - 委托代表一个函数的定义,用于说明函数长什么样,输入参数是什么、返回值是什么类型,但没有函数体。
delegate double Compute(double number1, double number2);
委托的作用
- 委托可以用来定义函数变量。
委托的使用
- 委托既然是一种数据类型那就可以用来申明变量。
- 委托数据类型的变量要赋值为一个函数。
- 赋值给委托变量的函数一定要和委托定义的函数原型一样,即输入参数和返回值一样。
- 赋值给委托变量的函数是一个有函数体的具体函数。好吧,这是句废话。
- 调用委托就是调用其对应的函数。
public double Add(double a, double b) { return a + b; } public void Test() { Compute c = Add; // 委托变量可以用来存一个具体的函数 Console.WriteLine(Add(1, 2)); // 输出:3。 Console.WriteLine(c(1, 2)); // 输出:3。变量可以用来替代其存储的数据,所以Add可以用c替代。 }
public double Add(double a, double b) { return a + b; } public double Sub(double a, double b) { return a - b; } public void Fun() { } public void Test() { // 申明委托变量 Compute c = Add; Console.WriteLine(c(1, 2)); // OK: 输出:3。 // 修改委托变量 // c = Fun; // ERROR: Fun函数的定义与Compute委托的定义不一致。 c = Sub; // OK: c是变量所以可以重新赋值。 Console.WriteLine(c(1, 2)); // 输出:-1。 }
委托的应用场景
上例中不是可以直接调用Add吗,为什么要用委托变量间接的调用呢?是的,这样做确实意义不大,完全可以不使用委托来实现。
- 委托变量通常不是在当前类中由自己来赋值的。而是由外部使用者来赋值。当前类中不知道调用哪个函数时才使用委托。
- 委托的使用场景主要有两种:事件和回调。
委托用于事件。事件是指当某个事情发生时去做什么,这种情况下要调用的函数无法事先预知,所以使用委托。
// 定义死亡委托 delegate void DeadHandler(); // 定义死亡事件 public DeadHandler Dead {get; set;} // 当被攻击时调用 void OnAttacked() { if (HP <= 0) { // 血量低于0就死亡了 if (Dead != null) Dead(); // 用户给Dead赋值为哪个函数,这里就会调用哪个函数。但当前类中并没有给Dead赋值,而是由交由使用者去赋值。 } }
委托用于回调。将委托作为函数参数来实现回调。(新手可以先忽略)
// complete: 下载完成的百分比;data:本次下载的数据。 delegate void DownloadHandler(double complete, byte[] data); // 下载函数。每当下载完一个缓存的数据,就会回调handler所指定的函数。 void Download(DownloadHandler handler) { if (handler!=null) handler(); }
委托传参(新手可以先忽略,后续补充)
常见错误
委托变量可以调用,委托类型是不能调用的。
// 定义死亡委托 delegate void DeadHandler(); // 当被攻击时调用 void Test() { // DeadHandler(); // ERROR:数据类型是不能直接调用的 DeadHandler dead = Fun; dead(); // OK: 调用dead变量,相当于调用了对应的Fun函数。 } void Fun() { }
给委托变量赋值时,函数名后加不加()。
// 定义死亡委托 delegate void DeadHandler(); // 当被攻击时调用 void Test() { DeadHandler dead; dead = Fun1; // OK: Fun1代表一个函数(的内存地址) // dead = Fun1(); // ERROR: Fun()是函数的调用,这里相当于使用了Fun()的返回值。 dead = Fun2(); // OK: Fun2()的返回值是DeadHandler类型与dead的类型一致。 } void Fun1() { } DeadHandler Fun2() { return Fun1; }