C# 林克:不是任何人对所有人,唐';T

C# 林克:不是任何人对所有人,唐';T,c#,.net,performance,linq,resharper,C#,.net,Performance,Linq,Resharper,我经常想检查提供的值是否与列表中的值匹配(例如,在验证时): 最近,我注意到ReSharper要求我将这些查询简化为: if (acceptedValues.All(v => v != someValue)) { // exception logic } 显然,这在逻辑上是相同的,也许可读性稍高一些(如果你做了大量的数学计算),我的问题是:这会导致性能下降吗 感觉应该是这样的(即,.Any()听起来像是短路,而.All()听起来好像不是),但我没有什么可以证实这一点。是否有人对查

我经常想检查提供的值是否与列表中的值匹配(例如,在验证时):

最近,我注意到ReSharper要求我将这些查询简化为:

if (acceptedValues.All(v => v != someValue))
{
    // exception logic
}
显然,这在逻辑上是相同的,也许可读性稍高一些(如果你做了大量的数学计算),我的问题是:这会导致性能下降吗


感觉应该是这样的(即,
.Any()
听起来像是短路,而
.All()
听起来好像不是),但我没有什么可以证实这一点。是否有人对查询是否会解决相同的问题有更深入的了解,或者ReSharper是否将我引入歧途?

第一次不匹配时,所有的
短路,所以这不是问题

一个微妙的方面是

 bool allEven = Enumerable.Empty<int>().All(i => i % 2 == 0); 
bool allEven=Enumerable.Empty().All(i=>i%2==0);
这是真的。序列中的所有项目都是偶数


有关此方法的更多信息,请参阅文档。

两者的性能相同,因为它们都在可以确定结果后停止枚举-
Any()
对传递的谓词计算为
true
All()的第一项
根据ILSpy,谓词在第一项上的计算结果为
false
实现
All
(就像我实际去看的那样,而不是“嗯,该方法有点像…”如果我们讨论的是理论而不是影响,我可能会这样做)

当然,产生的白细胞介素可能有一些细微的差别。但是没有,没有。IL几乎相同,但在谓词匹配时返回true与在谓词不匹配时返回false的明显相反

当然,这只是对象的linq。有可能其他的linq提供者对其中一个要比另一个好得多,但是如果是这样的话,那么哪一个得到了更优化的实现几乎是随机的

这条规则似乎只适用于那些认为
if(determineSomethingTrue)
if(!determineSomethingFalse)
更简单、更可读的人。公平地说,我认为他们有一点,我经常发现
if(!someTest)
令人困惑,当有一个同样详细和复杂的替代测试,对于我们想要采取行动的条件,它会返回true。但实际上,我个人认为,在你给出的两个选择中,没有什么比另一个更有利,如果谓词更复杂,我可能会稍微倾向于前者


*不是因为我不明白而感到困惑,而是因为我担心这个决定有一些微妙的原因,我不明白,这需要一些精神上的跳跃才能意识到“不,他们只是决定这样做,等等,我又在看这段代码干什么呢?”

您可能会发现这些扩展方法使代码更具可读性:

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.None(v => v == someValue))
{
    // exception logic
}
据此,

Any–检查至少一个匹配项

All–检查所有匹配项

All()
确定序列的所有元素是否满足条件。
Any()
确定序列的任何元素是否满足条件

var numbers = new[]{1,2,3};

numbers.All(n => n % 2 == 0); // returns false
numbers.Any(n => n % 2 == 0); // returns true

正如其他答案所涵盖的那样:这与性能无关,而是与清晰度有关

您的两种选择都有广泛的支持:

if (!acceptedValues.Any(v => v == someValue))
{
    // exception logic
}

if (acceptedValues.All(v => v != someValue))
{
    // exception logic
}
但我认为这可能会获得更广泛的支持:

在求反之前简单地计算布尔值(并给它命名),我的脑海中就清楚了很多。

如果你看一下,你会发现
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;
}
public static bool Any(此IEnumerable源代码,Func谓词){
if(source==null)抛出错误.ArgumentNull(“source”);
if(predicate==null)抛出Error.ArgumentNull(“predicate”);
foreach(源中的TSource元素){
if(谓词(元素))返回true;
}
返回false;
}
公共静态bool All(此IEnumerable源,Func谓词){
if(source==null)抛出错误.ArgumentNull(“source”);
if(predicate==null)抛出Error.ArgumentNull(“predicate”);
foreach(源中的TSource元素){
如果(!谓词(元素))返回false;
}
返回true;
}

一种方法不可能比另一种方法快很多,因为唯一的区别在于布尔求反,所以更喜欢可读性而不是伪性能赢。

您是否尝试过分解Linq代码以查看它在做什么?在这种情况下,我实际上会选择if(!acceptedValues.Contains(someValue)),但问题当然不是这样:)@csgero我同意。以上是对真实逻辑的简化(可能是过度简化),“感觉它应该(即,Any()听起来像短路,而.All()听起来像不短路)”——对任何有良好直觉的人来说都不是。您注意到的逻辑等价性意味着它们同样可以短路。片刻的思考表明,一旦遇到不符合条件的情况,所有人都可以退出。我并不完全同意ReSharper的观点。写出明智的思路。如果要在缺少必需项时引发异常:
If(!sequence.Any(v=>v==true))
。如果您希望仅在所有内容都符合特定规范时继续:
If(sequence.All(v=>v<10))
。是,但是
bool allEven=!Enumerable.Empty().Any(i=>i%2!=0)
也为true。@Jon语义上无!=全部的因此,从语义上讲,您要么拥有none,要么拥有all,但在.all()的情况下,none只是所有集合的子集,这些集合返回true for all,如果您不知道,这种差异可能会导致bug+我为此付1英镑Anthony@RuneFS我不明白。从语义和逻辑上来说,“在不真实的地方没有……”确实与“在真实的地方所有”相同。例如,“其中没有
if (acceptedValues.None(v => v == someValue))
{
    // exception logic
}
var numbers = new[]{1,2,3};

numbers.All(n => n % 2 == 0); // returns false
numbers.Any(n => n % 2 == 0); // returns true
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
}
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;
}