C# 图解教程 第5版 —— 第14章 委托

14.1 什么是委托

​ 委托会执行它所“持有”的方法,可以看成是类型安全、面向对象的 C++ 函数指针。

14.2 委托概述

​ 委托是一种用户定义类型,其与类的区别可简单概括如下:

  • 类是数据和方法的集合。
  • 委托持有一个或多个方法。

​ 委托类型的声明和方法类似,只是没有实现块。

image-20231031175517787
图14.1 与类相似,委托是用户定义的引用类型

​ 可以将 delegate 看作一个包含有序方法列表的对象,这些方法具有相同的签名和返回类型。

  • 方法的列表称为调用列表。
  • 方法可以来自任何类或结构,只要满足如下的匹配:
    • 委托的返回类型。
    • 委托的签名(包含 ref 和 out)。
  • 方法可以是实例方法或者静态方法。
  • 调用委托时,会执行调用列表中的所有方法。
image-20231031175844019
图14.2 把委托看成一个方法列表

14.3 声明委托类型

  • 以关键字 delegate 开头。
  • 没有方法主体。
  • 不需要在类内部声明,因为委托是类型声明。
image-20231031180011561
图14.3 声明委托类型
image-20231031180112100
图14.4 委托类型和对象

14.4 创建委托对象

​ 声明委托类型的变量:

image-20231031180225040
图14.5 声明委托类型的对象

​ 创建委托对象的两种方式:

  1. 使用 new 运算符。
image-20231031180332435
图14.6 使用 new 运算符声明委托对象
  1. 使用快捷语法。

    方法和委托类型之间存在隐式转换,该快捷语法利用了这一特性。

image-20231031180524255
图14.7 使用快捷语法声明委托对象
image-20231031180625615
图14.8 初始化委托

14.5 给委托赋值

​ 可以通过赋值改变包含在委托变量中的引用,旧的委托对象会被垃圾回收器回收。

image-20231101125404347
图14.9 给委托变量赋值

14.6 组合委托

​ 使用 + 组合委托,委托对象被创建后不能再被改变。

image-20231101130526417 image-20231101130544013
图14.10 组合委托

14.7 为委托添加方法

image-20231101130627550 image-20231101130640228
图14.11 为委托添加方法

​ 在使用 += 运算符时,实际发生的是创建了一个新的委托,其调用列表是左边的委托加上右边方法的组合,然后将这个新的委托赋值给 delVar

14.8 从委托移除方法

​ 在使用 -= 运算符时,实际上也是创建了一个新的委托。

  • 如果在调用列表中的方法有多个实例,则删除最后一个。
  • 可以删除委托中不存在的方法,结果没有影响。
image-20231101131316490
图14.12 从委托移除代码的结果

14.9 调用委托

  • 可以使用两种方法调用委托。
    1. 像方法一样调用。
    2. 使用 InVoke 调用。
  • 如果一个方法在调用列表中多次出现,则调用委托时会被多次执行。
  • 试图调用空委托将会抛出异常,需要判断委托是否为 null。
image-20231101131607711
图14.13 在调用委托时,它使用相同的参数来执行调用列表中的每一个方法

14.10 委托的示例(*)

14.11 调用带返回值的委托

  • 调用列表中最后一个方法的返回值就是调用委托的返回值。
  • 调用列表中之前方法的返回值都会被忽略。

14.12 调用带引用参数的委托

​ 如果委托中有引用参数,参数值可能会根据调用列表中的方法而改变。

​ 在调用委托列表中的下一个方法,参数的新值会被传给下一个方法。

14.13 匿名方法

​ 匿名方法是在实例化委托时内联声明的方法。

image-20231101132059494
图14.14 比较具名方法和匿名方法

14.13.1 使用匿名方法

​ 可以在以下情况中使用匿名方法:

  1. 声明委托变量时,充当初始化表达式。
  2. 组合委托时,充当赋值表达式。
  3. 为委托增加事件时,充当事件表达式。

14.13.2 匿名方法的语法

image-20231102114230863
图14.15 匿名方法的声明
  1. 返回类型

    匿名方法不会显示声明返回值,但必须返回与委托返回值相同类型的值。

image-20231102114405754
图14.16 匿名方法的返回类型
  1. 参数

    匿名方法可以省略圆括号进行简化,但需要满足如下两个条件:

    • 委托的参数列表不包含任何 out 参数。
    • 匿名方法不使用任何参数。
image-20231102114719024
图14.17 匿名方法的返回类型
  1. params 参数

    如果委托声明的参数列表中包含 params,那么匿名方法的参数列表不能使用 params 关键字。

    • 委托类型声明指定最后一个参数为 params 类型。
    • 匿名方法的参数列表必须不带 params。
image-20231102114918194 image-20231102114951856
图14.18 匿名方法中不需要声明 params 关键字

14.13.3 变量和参数的作用域

​ 参数及声明在匿名方法内部的局部变量的作用域限制在实现代码的主体之内。

image-20231102115135444
图14.19 变量和参数的作用域
  1. 外部变量

    匿名方法可以访问它们外围作用域的局部变量和环境。

    • 外围作用域的变量称为 外部变量
    • 用匿名方法实现代码中的外部变量称为 被方法捕获
image-20231102115404498
图14.20 使用外部变量
  1. 捕获变量生命周期的扩展

    只要捕获方法是委托的一部分,即使变量已经离开了作用域,捕获的外部变量也会一直有效。

image-20231102133143583 image-20231102133211642
图14.21 在匿名方法中捕获的变量

14.14 Lambda 表达式

​ C# 2.0 引入了匿名方法,C# 3.0 引入了 Lambda 表达式。可以使用 Lambda 表达式代替匿名方法:

  • 删除 delegate 关键字。
  • 使用 Lambda 运算符 =>
image-20231102133413865
图14.22 使用 Lmabda 表达式
  • 编译器可以从委托声明中直到委托参数的类型,因此 Lambda 表达式可以省略类型参数。
    • 显示类型:带有类型的参数列表。
    • 隐式类型:省略类型的参数列表。
  • 如果只有一个隐式类型参数,可以省略圆括号。
  • 如果语句块只包含一个返回语句,可以省略 return
image-20231102133707064
图14.23 Lmabda 表达式的简化
  • 若委托有 ref 或 out 参数,则 Lambda 表达式必须为显示类型。
  • 如果没有参数,必须使用一组空的圆括号。
image-20231102133839353
图14.24 Lmabda 表达式形式总结

猜你喜欢

转载自blog.csdn.net/zheliku/article/details/134180359