基本概念梳理
委托 (delegate) 是一种基于类的数据类型,功能类似于C++中的函数指针。该类型用于表示对于具有特定参数列表与返回类型的方法的引用。通俗来说,委托可以理解为持有一个或多个方法的对象。如果执行委托的话,委托会执行它所"持有"的方法。委托可以提高程序的可扩展性与灵活性。
本质上来看委托和类相似,都是一种用户自定义的类型。不过类表示的是数据和方法的集合,而委托则持有一个或多个方法,以及一系列预定义的操作。
事件 (event) 是基于委托的进一步封装,在使用上可以将它视作一个委托类型的变量。在用事件进行封装后,用户对于委托链上方法的操作权限受到适当的限制,用户只能够通过+=
、-=
操作符来进行外部方法的注册与注销,而不能使用=
操作符来对委托进行直接赋值。增强了后续编码时的安全性。
相关要点
匿名方法与Lambda表达式
匿名方法是没有命名标识的方法,通常用于直接创建委托实例,而无需先定义一个独立的命名方法。它可以直接作为委托类型参数的一段代码,从而简化了“先声明方法,再传递给委托”的步骤。而Lambda表达式基本可以看作是匿名方法的另一种写法,其主要优势在于提供了更简洁的语法来定义委托实例。详见 DWHITE/3_编程与开发/CS/CSharp_Lambda表达式。
注意 两者都是用于配合委托(事件)使用的子概念,可以说没什么好深究的
Fun<int, int> anon = delegate(int i) {
return ++i;
}
内置委托:Action
、 Func
内置委托有:
Action
:接受 0 到 16 个参数,用于没有返回值的方法;适合只需要“执行”操作的场景。Func
:接受 0 到 16 个参数,用于有返回值的方法,最后一个泛型参数为返回值类型;适合需要运算或计算结果后返回值的场景。Predicate
:用于判断条件的方法;返回布尔值,多用于集合过滤、查找等。EventHandler
:专门用于事件处理,确保事件触发时包含发送者和事件数据。
其中Action
相对常用,例如下面:
PrintMessage()
方法与 Action 委托的签名匹配(无参数、返回 void)。- 通过
Action action = PrintMessage;
把方法传给委托,然后调用action()
来执行该方法。
using System;
class Program
{
static void Main()
{
// 将 PrintMessage 方法赋值给 Action 委托
Action action = PrintMessage;
// 调用委托,从而执行 PrintMessage 方法
action();
}
// 定义一个无参数且无返回值的方法
static void PrintMessage()
{
Console.WriteLine("Hello, Action!");
}
}
多使用内置委托,而不是频繁定义新的委托
多播委托(委托链 / 链式委托)
即一个委托可以指向多个适配的方法。使用+=
运算符可以将多个方法添加到委托中,使用-=
运算符可以从委托中移除方法。在委托执行时,将按照方法的注册顺序依次调用。
附
附1:C#的委托与C++的函数指针相比
C#委托 | C/C++ 函数指针 | |
---|---|---|
存储内容 | 对象实例+方法地址 | 函数地址 |
对象绑定 | 自带绑定对象实例 | 需要手动处理指定 |
安全性 | 类型安全,签名匹配,强类型检查 | 类型安全弱 |
面向对象 | 很面向对象,封装了方法及其对象实例 | 更像是过程式编程风格 |