14.1 什么是委托
委托是持有一个或多个方法的对象,执行委托时,委托会执行它所“持有”的所有方法。
14.2 委托概述
使用委托的步骤:
- 声明一个委托类型
- 使用该类型声明一个委托变量;
- 创建一个委托类型的对象,并将其赋值给委托变量;
- 可以为委托对象添加其他方法;
- 在代码中像调用方法那样调用委托。委托中包含的方法会被依次执行。
14.3 声明委托类型
delegate void MyDel(int x);
类似于方法的声明,声明委托类型需要关键字,返回类型,委托类型名,参数列表。注意:
- 不需要方法主体(代码块);
- 不需要在类内声明,因为它是类型声明。
14.4 创建委托对象
delegate void MyDel(int x);
class MyClass
{
static public void MyStatic(int x)
{
Console.WriteLine("x = {0}", x);
}
public void MyMethod(int y)
{
Console.WriteLine("y = {0}", y);
}
}
class Program
{
static void Main()
{
MyClass mc = new MyClass();
// 创建两个委托对象
MyDel del1 = new MyDel(MyClass.MyStatic);
MyDel del2 = new MyDel(mc.MyMethod);
// 快捷语法
//MyDel del1 = MyClass.MyStatic;
//MyDel del2 = mc.MyMethod;
}
}
14.5 给委托赋值
委托是引用类型,可以通过给它赋值来改变包含在委托中的引用。旧的委托对象会被垃圾回收器回收。
14.6 组合委托
MyDel del1 = MyClass.MyStatic;
MyDel del2 = mc.MyMethod;
MyDel del3 = del1 + del2; // del1 和 del2 不会被改变
14.7 为委托添加方法
MyDel del1 = MyClass.MyStatic;
del1 += mc.MyMethod; // 可以直接使用 +=
实际上在使用+=
时我们创建了一个新的委托。
14.8 从委托移除方法
类似于+=
,移除方法用-=
即可。注意:
- 如果调用列表中的方法有多个实例,
-=
运算符将从列表最后开始搜索; - 不能删除委托中不存在的方法;
- 调用空委托会抛出异常,调用前应先将委托和
null
进行比较。
14.9 调用委托
// 方法一
if (del3 != null)
del3(42);
// 方法二
del3.Invoke(42);
14.10 委托的实例
略
14.11 调用带返回值的委托
- 委托调用的返回值就是最后一个方法返回的值;
- 其他方法的返回值会被忽略。
14.12 调用带引用参数的委托
由于调用列表中的方法是依次执行的,所以每一个方法返回后,参数的新值会传给下一个方法。
14.13 匿名方法
namespace Test
{
delegate int MyDel(int x);
class Program
{
static void Main()
{
MyDel del1 = delegate (int x) // 匿名方法
{
return x + 1;
};
Console.WriteLine("{0}", del1(5));
}
}
}
14.13.2 匿名方法的语法
delegate ( Parameters ) { ImplementationCode }
语法细节:
- 匿名方法不会显式声明返回值,但是实现代码本身的行为必须通过返回一个与委托的返回类型相同的值来匹配委托的返回类型;
- 匿名方法的参数列表需要在参数数量、类型及位置、修饰符都和委托匹配;
- 如果委托的参数列表不包含任何
out
参数,并且匿名方法不使用任何参数,可以省略匿名方法的参数列表。 - 如果委托的参数列表包含
params
参数,匿名方法的参数列表将忽略params
关键字。
14.13.3 变量和参数的作用域
static void Main()
{
MyDel del1;
{
int outerVar = 10000;
del1 = delegate (int x)
{ // 匿名方法可以访问它们外围作用域的局部变量
return x + outerVar + 1;
};
}
//Console.WriteLine("{0}", outerVar); // 错误
Console.WriteLine("{0}", del1(0)); // 正确,扩展了 outerVar 的生命周期
}
匿名方法可以访问它们外围作用域的局部变量,此时,称外部变量被方法捕获。
14.14 Lambda 表达式
可以用来替代匿名方法,详见 P271。