LINQ:不是所有的vs都没有。

时间:2021-06-15 04:12:54

Often I want to check if a provided value matches one in a list (e.g. when validating):

通常我想要检查一个提供的值是否匹配列表中的一个值(例如,验证时):

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

Recently, I've noticed ReSharper asking me to simplify these queries to:

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

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

Obviously, this is logically identical, perhaps slightly more readable (if you've done a lot of mathematics), my question is: does this result in a performance hit?

显然,这在逻辑上是相同的,可能稍微更容易理解(如果您做了大量的数学),我的问题是:这会导致性能下降吗?

It feels like it should (i.e. .Any() sounds like it short-circuits, whereas .All() sounds like it does not), but I have nothing to substantiate this. Does anyone have deeper knowledge as to whether the queries will resolve the same, or whether ReSharper is leading me astray?

我觉得它应该(也就是说,任何()听起来都像是短路,而. all()听起来好像没有,但我没有任何证据可以证实这一点。有没有人对查询是否会解决问题有更深入的了解,或者ReSharper是否会把我引入歧途?

8 个解决方案

#1


284  

Implementation of All according to ILSpy (as in I actually went and looked, rather than the "well, that method works a bit like ..." I might do if we were discussing the theory rather than the impact).

根据ILSpy(我实际上是去查看,而不是“嗯,那个方法有点像…”)的实现。如果我们讨论的是理论而不是影响,我可能会这样做。

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

Implementation of Any according to ILSpy:

根据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;
}

Of course, there could be some subtle difference in the IL produced. But no, no there isn't. The IL is pretty much the same but for the obvious inversion of returning true on predicate match versus returning false on predicate mismatch.

当然,IL的产生可能有一些细微的差别。但是没有,没有。IL几乎是相同的,但对于明显的反演,在谓词匹配上返回true,而在谓词不匹配上返回false。

This is linq-for-objects only of course. It's possible that some other linq provider treats one much better than the other, but then if that was the case, it's pretty much random which one got the more optimal implementation.

这当然是linq-for-objects。有可能其他的linq提供程序比另一个更好,但是如果是这样的话,它是非常随机的,哪一个得到了更优的实现。

It would seem that the rule comes down solely to someone feeling that if(determineSomethingTrue) is simpler and more readable than if(!determineSomethingFalse). And in fairness, I think they've a bit of a point in that I often find if(!someTest) confusing* when there's an alternative test of equal verbosity and complexity that would return true for the condition we want to act upon. Yet really, I personally find nothing to favour one over the other of the two alternatives you give, and would perhaps lean very slightly toward the former if the predicate were more complicated.

似乎这条规则只会让人觉得,如果(决定了)比(!)更简单,更可读。公平地说,我认为他们有一点是我经常发现的,如果(某些测试)令人困惑*当有另一种相同的冗长和复杂性的测试时,我们想要采取行动的条件就会返回。然而,实际上,我个人认为,在你给出的两种选择中,没有什么比这更有利于你的了,如果谓词更复杂的话,你可能会倾向于前者。

*Not confusing as in I don't understand, but confusing as in I worry that there's some subtle reason for the decision that I don't understand, and it takes a few mental skips to realise that "no, they just decided to do it that way, wait what was I looking at this bit of code for again?..."

*不混乱,我不明白,但令人困惑的我担心有一些微妙的理由我不理解的决定,和需要一些精神跳过意识到,“不,他们就决定这样做,等我查看这个代码是什么?……”

#2


46  

You might find these extension methods make your code more readable:

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

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

Now instead of your original

而不是你原来的。

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

you could say

你可能会说

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

#3


21  

Both would have identical performance because both stop enumeration after the outcome can be determined - Any() on the first item the passed predicate evaluates to true and All() on the first item the predicate evaluates to false.

两种方法都具有相同的性能,因为在结果可以确定的情况下都停止枚举——在第一个项上,通过的谓词计算为true,所有()在第一个项上,谓词计算为false。

#4


16  

All short circuits on the first non-match, so it's not a problem.

所有的短路都是在第一个不匹配的,所以这不是一个问题。

One area of subtlety is that

其中一个微妙的地方是。

 bool allEven = Enumerable.Empty<int>().All(i => i % 2 == 0); 

Is true. All of the items in the sequence are even.

是真的。序列中的所有项都是偶数。

For more on this method, consult the documentation for Enumerable.All.

有关此方法的更多信息,请参阅文档以获得枚举。

#5


4  

As other answers have well covered: this is not about performance, it's about clarity.

正如其他答案所涵盖的:这不是关于性能的,而是关于清晰度的。

There's wide support for both of your options:

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

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

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

But I think this might achieve broader support:

但我认为这可能会获得更广泛的支持:

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

Simply computing the boolean (and naming it) before negating anything clears this up a lot in my mind.

在否定任何东西之前,只需计算布尔值(并命名它)就可以在我的脑海中理清很多事情。

#6


3  

If you take a look at the Enumerable source you'll see that the implementation of Any and All is quite close:

如果您查看一下可枚举的源代码,您将看到任何和所有的实现都非常接近:

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

There is no way that one method be significantly faster than the other since the only difference lies in a boolean negation, so prefer readability over false performance win.

因为唯一的区别在于布尔式的否定,所以一种方法比另一种方法要快得多,所以更喜欢可读性胜过错误的性能。

#7


2  

All() determines whether all elements of a sequence satisfy a condition.
Any() determines whether any element of a sequence satisfies the condition.

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

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

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

#8


1  

According to this link

根据这个链接

Any – Checks for at least one match

任何-检查至少一根火柴。

All – Checks that all match

所有-检查所有匹配。

#1


284  

Implementation of All according to ILSpy (as in I actually went and looked, rather than the "well, that method works a bit like ..." I might do if we were discussing the theory rather than the impact).

根据ILSpy(我实际上是去查看,而不是“嗯,那个方法有点像…”)的实现。如果我们讨论的是理论而不是影响,我可能会这样做。

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

Implementation of Any according to ILSpy:

根据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;
}

Of course, there could be some subtle difference in the IL produced. But no, no there isn't. The IL is pretty much the same but for the obvious inversion of returning true on predicate match versus returning false on predicate mismatch.

当然,IL的产生可能有一些细微的差别。但是没有,没有。IL几乎是相同的,但对于明显的反演,在谓词匹配上返回true,而在谓词不匹配上返回false。

This is linq-for-objects only of course. It's possible that some other linq provider treats one much better than the other, but then if that was the case, it's pretty much random which one got the more optimal implementation.

这当然是linq-for-objects。有可能其他的linq提供程序比另一个更好,但是如果是这样的话,它是非常随机的,哪一个得到了更优的实现。

It would seem that the rule comes down solely to someone feeling that if(determineSomethingTrue) is simpler and more readable than if(!determineSomethingFalse). And in fairness, I think they've a bit of a point in that I often find if(!someTest) confusing* when there's an alternative test of equal verbosity and complexity that would return true for the condition we want to act upon. Yet really, I personally find nothing to favour one over the other of the two alternatives you give, and would perhaps lean very slightly toward the former if the predicate were more complicated.

似乎这条规则只会让人觉得,如果(决定了)比(!)更简单,更可读。公平地说,我认为他们有一点是我经常发现的,如果(某些测试)令人困惑*当有另一种相同的冗长和复杂性的测试时,我们想要采取行动的条件就会返回。然而,实际上,我个人认为,在你给出的两种选择中,没有什么比这更有利于你的了,如果谓词更复杂的话,你可能会倾向于前者。

*Not confusing as in I don't understand, but confusing as in I worry that there's some subtle reason for the decision that I don't understand, and it takes a few mental skips to realise that "no, they just decided to do it that way, wait what was I looking at this bit of code for again?..."

*不混乱,我不明白,但令人困惑的我担心有一些微妙的理由我不理解的决定,和需要一些精神跳过意识到,“不,他们就决定这样做,等我查看这个代码是什么?……”

#2


46  

You might find these extension methods make your code more readable:

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

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

Now instead of your original

而不是你原来的。

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

you could say

你可能会说

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

#3


21  

Both would have identical performance because both stop enumeration after the outcome can be determined - Any() on the first item the passed predicate evaluates to true and All() on the first item the predicate evaluates to false.

两种方法都具有相同的性能,因为在结果可以确定的情况下都停止枚举——在第一个项上,通过的谓词计算为true,所有()在第一个项上,谓词计算为false。

#4


16  

All short circuits on the first non-match, so it's not a problem.

所有的短路都是在第一个不匹配的,所以这不是一个问题。

One area of subtlety is that

其中一个微妙的地方是。

 bool allEven = Enumerable.Empty<int>().All(i => i % 2 == 0); 

Is true. All of the items in the sequence are even.

是真的。序列中的所有项都是偶数。

For more on this method, consult the documentation for Enumerable.All.

有关此方法的更多信息,请参阅文档以获得枚举。

#5


4  

As other answers have well covered: this is not about performance, it's about clarity.

正如其他答案所涵盖的:这不是关于性能的,而是关于清晰度的。

There's wide support for both of your options:

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

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

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

But I think this might achieve broader support:

但我认为这可能会获得更广泛的支持:

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

Simply computing the boolean (and naming it) before negating anything clears this up a lot in my mind.

在否定任何东西之前,只需计算布尔值(并命名它)就可以在我的脑海中理清很多事情。

#6


3  

If you take a look at the Enumerable source you'll see that the implementation of Any and All is quite close:

如果您查看一下可枚举的源代码,您将看到任何和所有的实现都非常接近:

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

There is no way that one method be significantly faster than the other since the only difference lies in a boolean negation, so prefer readability over false performance win.

因为唯一的区别在于布尔式的否定,所以一种方法比另一种方法要快得多,所以更喜欢可读性胜过错误的性能。

#7


2  

All() determines whether all elements of a sequence satisfy a condition.
Any() determines whether any element of a sequence satisfies the condition.

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

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

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

#8


1  

According to this link

根据这个链接

Any – Checks for at least one match

任何-检查至少一根火柴。

All – Checks that all match

所有-检查所有匹配。