在上一篇文章中,你已看到你使用 delegate
关键字创建特定的委托类型。
抽象委托类提供用于松散耦合和调用的基础结构。 通过包含和实施添加到委托对象的调用列表的方法的类型安全性,具体的委托类型将变得更加有用。 使用 delegate
关键字并定义具体的委托类型时,编译器将生成这些方法。
实际上,每当需要其他方法签名时,这都会导致创建新的委托类型。 这项工作在一段时间后可能会很繁琐。 每个新功能都需要新的委托类型。
值得庆幸的是,这不是必要的。 .NET Core 框架包含多种类型,只要需要委托类型,就可以重复使用这些类型。 这些是 泛型 定义,因此当需要新的方法声明时,可以声明自定义项。
这些类型中的第一个是 Action 类型,以及几个变体:
public delegate void Action();
public delegate void Action<in T>(T arg);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
// Other variations removed for brevity.
泛型类型参数上的in
修饰符在有关协变的文章中有详细介绍。
委托的变体 Action
最多包含 16 个参数,例如 Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>。
重要的是,这些定义对每个委托参数使用不同的泛型参数:这为你提供了最大的灵活性。 方法参数不需要相同类型,但可能相同。
对任何具有 void 返回类型的委托类型使用一种 Action
类型。
该框架还包括多个泛型委托类型,可用于返回值的委托类型:
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>(T1 arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
// Other variations removed for brevity
out
结果泛型类型参数上的修饰符涵盖在关于协变的文章中。
Func
委托的变体可包含多达 16 个输入参数,如 Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult>。
按照约定,结果的类型始终是所有声明中的最后 Func
一个类型参数。
对任何返回值的委托类型使用一种 Func
类型。
还有一种专门的委托类型 Predicate<T>,此类型返回单个值的测试结果:
public delegate bool Predicate<in T>(T obj);
你可能会注意到,对于任何 Predicate
类型,结构上等效 Func
的类型存在例如:
Func<string, bool> TestForString;
Predicate<string> AnotherTestForString;
你可能会认为这两种类型是等效的。 他们不是。 这两个变量不能互换使用。 无法为一种类型的变量分配另一种类型。 C# 类型系统使用定义的类型的名称,而不是结构。
.NET Core 库中的所有这些委托类型定义都应意味着无需为需要委托的任何新功能定义新的委托类型。 这些泛型定义应提供大多数情况下所需的所有委托类型。 只需使用所需的类型参数实例化其中一种类型。 对于可以进行泛型的算法,这些委托可用作泛型类型。
这样可以节省时间,并尽量减少为了使用委托而需要创建的新类型的数目。
在下一篇文章中,你将看到在实践中使用委托的几种通用模式。