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源代码,你会发现AnyAll的实现非常接近:

 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一场比赛

全部 – 全部匹配