委托
委托和类一样,是一种用户自定义的类型。但类表示的是数据的集合,而委托保存的是方法的集合。
可以把委托看做一个包含有序方法列表的对象,即委托是一列方法,这些方法具有相同的签名和返回类型。
1.列方法叫做调用列表。
2.委托保存的方法可以来自任何类或结构,只要它们符合委托的返回类型和签名(包括ref和out修饰符)。
3.调用列表中的方法可以是实例方法也可以是静态方法。
4.在调用委托的时候,会执行其调用用表中的所有方法。
- 使用委托的步骤
1.使用特定签名和返回类型声明一个新的委托类型。委托类型看上去和方法声明相似,只是没有实现块。
2.使用新的委托类型声明委托变量。
3.创建委托类型的对象,把它赋值给委托变量。新的委托对象包括指向方法的引用,这个方法和第一步定义的签名一致。
4.为委托对象增加其他方法。这些方法必须与第一步中定义的委托类型有相同的签名和返回类型。
5.在代码中你可以像调用方法一样调用委托。在调用委托的时候,其包含的每一个方法都会被执行。
- 创建委托对象
有两种创建委托对象的方式,第一种是使用带new运算符的对象创建表示式,第二种是使用快捷语法。
new运算符的操作符是由委托类型名和圆括号组成,圆括号包含了调用列表中第一个成员的方法的名字,方法可以是实例方法或者静态方法。
快捷语法仅由方法说明符构成,使用快捷语法是因为在方法名称和其相应的委托类型之间有隐式转换。
eg:Program program = new Program();
GetDivide getDivide = new GetDivide(GetResultstatic);
GetDivide divide = new GetDivide(program.GetResult);
GetDivide getDivide2 = GetResultstatic;
GetDivide divide2 = program.GetResult;
- 赋值委托
委托是引用类型,可以通过给委托类型的变量赋值来改变变量中的引用,旧的委托对象会被GC回收。
- 组合委托
组合委托可以使两个委托组合成新的委托,新的委托的调用列表为两个委托的调用列表的副本。
eg:GetDivide getDivide = new GetDivide(GetResultstatic);
GetDivide divide = new GetDivide(program.GetResult);
GetDivide divide2 = program.GetResult;
divide2 = getDivide + divide;
- 委托增加方法
使用+=运算符,可以为委托的调用列表增加新的方法,新的方法加在调用列表的底部。相同的方法也会叠加,即相同的方法会重复调用。
使用+=运算符时,实际发生创建了新的委托,其调用列表是左边的委托加上右边的方法的组合,然后新的委托给变量赋值。
eg:GetDivide divide2 = program.GetResult;
divide2+=program.GetResult;
- 委托移除方法
使用-=运算符时,实际发生创建了新的委托,其调用列表是旧委托移除了方法的新组合。
如果在调用列表中的方法有多个实例,-=运算符将从列表最后开始搜索,并且移除第一个与方法匹配的实例。
试图删除委托中不存在的方法没有效果。
试图调用空委托会抛出异常。
把委托和null进行比较来判断委托的调用列表是否为空。如果调用列表为空,则委托是null。
- 调用委托
用于调用委托的参数将会用于调用调用列表中的每一个方法。
eg:GetDivide divide2 = program.GetResult;
divide2+=program.GetResult;
divide2(1)=> program.GetResult(1);
program.GetResult(1);
- 调用带返回值的委托
如果委托有返回值并且在调用列表中有一个以上的列表,则调用列表中最后一个方法返回的值就是委托调用返回的值,调用列表中所有其他方法的返回值都会被忽略。
- 调用带引用参数的委托
如果委托有引用参数,参数值会根据调用列表中的方法的返回值而改变。
在调用列表中的下一个方法时,参数的新值而不是初始值会传给下一个方法。
1.调用匿名方法的委托
匿名方法是在初始化委托时内联声明的方法。匿名方法不能使用跳转语句;而且不能访问匿名方法外的使用ref和out参数,这样都是不安全的行为。匿名方法的语法在C#2.0时引入,但是被C#3.0引入的Lambda表达式替代。
private static void Main()
{
//无参匿名方式
Func<int> action = delegate ()
{
return 1;
};
Console.WriteLine(action());
}
private static void Main()
{
//无参Lambda表达式
Func<int> action = () =>
{
return 1;
};
Console.WriteLine(action());
}
2.使用匿名方法的地方
声明委托变量时作为初始化表达式。
组合委托时在赋值语句的右边。
为委托增加事件时在赋值语句的右边。
3.变量和参数的作用域
参数以及声明在匿名方法内部的局部变量的作用域限制在实现方法的主题之内。
3.1外部变量
与委托的命名方法不同,匿名方法可疑访问它们外围作用域的局部变量和环境。
外围作用域的变量叫做外部变量。
用在匿名方法实现代码中的外部变量成为被方法捕获,
3.2 被捕获变量的生命周期的扩展
只要捕获方法还是委托的一部分,即使变量已经离开了作用域,被捕获的外部变量也会一直有效。