C#中的可选委托

这是两个扩展方法重载的简单示例

public static class Extended { public static IEnumerable Even(this List numbers) { return numbers.Where(num=> num % 2 == 0); } public static IEnumerable Even(this List numbers, Predicate predicate) { return numbers.Where(num=> num % 2 == 0 && predicate(num)); } } 

通过将委托设置为可选,我希望能够将它们合并为一个:

 public static class Extended { public static IEnumerable Even(this List numbers, Predicate predicate = alwaysTrue) { return numbers.Where(num=> num % 2 == 0 && predicate(num)); } public static bool alwaysTrue(int a) { return true; } } 

但是,编译器抛出一个错误:

‘predicate’的默认参数值必须是编译时常量

我没有看到我的alwaysTrue函数是如何不恒定的,但是嘿,编译器知道的更好:)

有没有办法让delegate参数可选?

它不是常量,因为你已经从方法组创建了一个委托……就C#语言而言,这不是编译时常量。

如果你不介意略微滥用null的含义,你可以使用:

 private static readonly Predicate AlwaysTrue = ignored => true; public static List Even(this List numbers, Predicate predicate = null) { predicate = predicate ?? AlwaysTrue; return numbers.Where(num=> num % 2 == 0 && predicate(num)); } 

(您仍然可以使AlwaysTrue成为方法并使用方法组转换,但通过仅创建一次委托实例,上述方法的效率会略高一些。)

你要做的是让它为null ,然后将其视为始终为真

您有两个选项,将代码加倍以省略委托调用,在未通过委托的情况下执行速度会更快。

 public static List Even(this List numbers, Predicate predicate = null) { if (predicate == null) return numbers.Where(num=> num % 2 == 0).ToList(); else return numbers.Where(num=> num % 2 == 0 && predicate(num)).ToList(); } 

或者,根据需要提供虚拟实现:

 public static List Even(this List numbers, Predicate predicate = null) { predicate = predicate ?? new Predicate(alwaysTrue); return numbers.Where(num=> num % 2 == 0 && predicate(num)).ToList(); } 

另外,考虑一下你是否真的想这样做。 可选参数对编译代码的影响是调用代码现在提供默认值,这意味着它将始终调用带有列表和委托的重载。

如果您以后想要返回,则需要确保重新编译调用该方法的所有代码,因为它不会神奇地开始使用不提供委托的方法。

换句话说,这个电话:

 var even = list.Even(); 

看起来像是这样写的:

 var even = list.Even(null); 

如果现在再次将方法更改为重载,如果不重新编译上述调用,则它将始终使用委托调用该方法,只为该参数提供null

您可以使用null -default值:

 public static class Extended { public static IEnumerable Even(this IEnumerable numbers, Predicate predicate = null) { if (predicate==null) { predicate = i=>true; } return numbers.Where(num => num % 2 == 0 && predicate(num)); } } 
 public static List Even(this List numbers, Predicate predicate = null) { return numbers.Where(num=> num % 2 == 0 && (predicate == null || predicate(num))); }