LINQ:没有任何与所有不
通常我想检查提供的值是否与列表中的值匹配(例如,validation时):
if (!acceptedValues.Any(v => v == someValue)) { // exception logic }
最近,我注意到ReSharper要求我简化这些查询:
if (acceptedValues.All(v => v != someValue)) { // exception logic }
显然,这在逻辑上是相同的,也许稍微有点可读性(如果你已经做了很多的math),我的问题是:这是否会导致性能下降?
它感觉就像应该(即.Any()
听起来像短路,而.All()
听起来像不),但我没有什么证实这一点。 有没有人对这些疑问是否能解决问题有更深入的了解,或者ReSharper是否把我引入歧途?
根据ILSpy实现All
(正如我实际上去看过的那样,而不是“好吧,那个方法有点像…”,如果我们讨论的是理论而不是影响)。
public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) { throw Error.ArgumentNull("source"); } if (predicate == null) { throw Error.ArgumentNull("predicate"); } foreach (TSource current in source) { if (!predicate(current)) { return false; } } return true; }
Any
根据ILSpy的实施:
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) { throw Error.ArgumentNull("source"); } if (predicate == null) { throw Error.ArgumentNull("predicate"); } foreach (TSource current in source) { if (predicate(current)) { return true; } } return false; }
当然,在IL中可能会有一些细微的差别。 但是,不,没有。 IL几乎是相同的,但是对于谓词匹配返回true的显而易见的倒置与在谓词不匹配上返回false相反。
这当然只是对象而已。 其他一些linq提供程序可能会比另一个更好,但是如果是这样的话,那么随机获得更好的实现是非常随机的。
看起来,这个规则只能归结为某人认为if(determineSomethingTrue)
比if(!determineSomethingFalse)
更简单,更易读。 公平地说,我认为他们有一点我经常发现, if(!someTest)
有一个相同冗长和复杂性的替代testing,那么我们经常会发现, if(!someTest)
我们想要采取行动的条件将会变成真实的。 但实际上,我个人觉得没有什么比这两个select中的另一个更赞成,如果谓词比较复杂的话,也许会对前者稍微倾斜。
*不要混淆,因为我不明白,但混乱,因为我担心,这个决定有一些微妙的原因,我不明白,这需要一些心理跳跃,意识到“不,他们只是决定做那么,等等我再看看这段代码是怎么回事?“
你可能会发现这些扩展方法使你的代码更具可读性:
public static bool None<TSource>(this IEnumerable<TSource> source) { return !source.Any(); } public static bool None<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { return !source.Any(predicate); }
现在,而不是你的原来的
if (!acceptedValues.Any(v => v == someValue)) { // exception logic }
你可以说
if (acceptedValues.None(v => v == someValue)) { // exception logic }
两者都具有相同的性能,因为都可以确定结果后停止枚举 – 传递谓词的第一个项目的Any()
将评估为true
并且第一个项目上的All()
将谓词评估为false
。
All
短路在第一次不匹配,所以这不是一个问题。
一个微妙的领域就是这个
bool allEven = Enumerable.Empty<int>().All(i => i % 2 == 0);
是真的。 序列中的所有项目都是偶数。
有关此方法的更多信息,请参阅Enumerable.All的文档。
正如其他答案所涵盖的:这不是关于performance,而是关于清晰度。
有广泛的支持你的两个select:
if (!acceptedValues.Any(v => v == someValue)) { // exception logic } if (acceptedValues.All(v => v != someValue)) { // exception logic }
但我认为这可能会得到更广泛的支持 :
var isValueAccepted = acceptedValues.Any(v => v == someValue); if (!isValueAccepted) { // exception logic }
在否定任何事情之前简单地计算布尔(并命名它)在我的脑海里就清除了这一点。
All()
确定序列的所有元素是否满足条件。
Any()
确定序列中的任何元素是否满足条件。
var numbers = new[]{1,2,3}; numbers.All(n => n % 2 == 0); // returns false numbers.Any(n => n % 2 == 0); // returns true
如果你看看Enumerable源代码,你会发现Any
和All
的实现非常接近:
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull("source"); if (predicate == null) throw Error.ArgumentNull("predicate"); foreach (TSource element in source) { if (predicate(element)) return true; } return false; } public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull("source"); if (predicate == null) throw Error.ArgumentNull("predicate"); foreach (TSource element in source) { if (!predicate(element)) return false; } return true; }
没有办法,一种方法比另一种显着更快,因为唯一的区别在于布尔否定,所以偏好可读性胜过虚假的performance。
根据这个链接
任何 – 检查至less一场比赛
全部 – 全部匹配