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))); }