在 C# 中,Action、Func 和 Predicate 是预定义委托类型,请说明它们的定义、区别以及在实际编码中如何选择和使用?
考察说明
考查对 C# 预定义委托类型的理解与实际应用能力。
回答思路
- 【回答框架 1】Action 委托封装无返回值的方法,可接受 0 到 16 个参数,常用于事件处理或回调。Func 委托必须返回一个值,最后一个泛型参数是返回类型,前面是参数类型,最多支持 16 个参数。Predicate 专门用于定义返回 bool 的方法,通常用于集合筛选或条件判断。
- 【回答框架 2】使用方式上,可以直接用 lambda 表达式、匿名方法或方法组赋值给委托实例。例如:Action<string> print = Console.WriteLine; Func<int, int> square = x => x * x; Predicate<int> isPositive = x => x > 0; 这些委托类型简化了代码,避免自定义委托声明。
- 【回答框架 3】选择时,根据方法是否有返回值决定:无返回值用 Action,有返回值用 Func,返回 bool 的拒绝谓词用 Predicate。实际开发中,这些委托广泛应用于 LINQ 查询、异步编程、事件订阅以及依赖注入容器。
- 【回答框架 4】在 LINQ 中,Where 方法接受 Func<T, bool> 或 Predicate<T>,但 Where 实际定义为 Func<T, bool>,而 List<T>.FindAll 等方法接受 Predicate<T>,需注意不同 API 的签名兼容性。
- 【回答框架 5】性能方面,委托调用有轻微开销,但现代 .NET 运行时已优化,通常不是热点路径的瓶颈。使用 lambda 表达式时注意闭包捕获变量可能带来额外内存分配,但在大多数业务场景可忽略。
- 【关键点 1】Action 无返回值,Func 有返回值,Predicate 返回 bool,三者核心区别在于返回类型。
- 【关键点 2】Func 的最后一个泛型参数是返回类型,前面按顺序是参数类型,例如 Func<int, string> 表示传入 int 返回 string。
- 【关键点 3】Predicate<T> 等价于 Func<T, bool>,但语义更明确,常用于集合查找或筛选。
- 【关键点 4】实际选择依据:方法是否有返回值及返回值类型,无返回值用 Action,有返回值用 Func,返回 bool 且用于判断则用 Predicate。
- 【关键点 5】委托可配合 lambda、匿名方法或方法组使用,需注意委托的协变和逆变支持,增强灵活性。
- 【易错点 1】混淆 Func 的泛型参数顺序,例如将返回类型放在中间,导致编译错误。
- 【易错点 2】在调用接受特定委托类型的 API 时,忽略显式转换要求,直接传入不匹配的 lambda 导致类型转换失败。
- 【易错点 3】忽略委托的异步版本如 Func<Task>,导致异步代码在同步上下文中被阻塞,引起死锁或性能问题。