LINQ:不是任何与全部不

发布于 2024-12-29 06:12:22 字数 476 浏览 3 评论 0原文

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

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

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

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

显然,这在逻辑上是相同的,也许更具可读性(如果您'我做了很多数学工作),我的问题是:这会导致性能下降吗?

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

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:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

書生途 2025-01-05 06:12:23

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

根据 ILSpy 实现 Any

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-for-objects。某些其他 linq 提供程序可能会比另一个提供程序更好地对待其中一个,但如果是这种情况,则哪个提供程序获得更优化的实现几乎是随机的。

看起来这条规则只是因为有人觉得 if(defineSomethingTrue)if(!defineSomethingFalse) 更简单、更易读。公平地说,我认为他们有一点道理,因为我经常发现 if(!someTest) 令人困惑*,当存在同等冗长和复杂性的替代测试时,该测试将为条件返回 true我们希望采取行动。但实际上,我个人认为您提供的两种选择中没有什么比另一种更有利的,并且如果谓词更复杂,也许会稍微倾向于前者。

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

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).

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:

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.

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.

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?..."

蓝色星空 2025-01-05 06:12:23

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

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
}

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
}
我乃一代侩神 2025-01-05 06:12:23

两者将具有相同的性能,因为两者在确定结果后都停止枚举 - 在传递谓词的第一个项目上的 Any() 计算结果为 trueAll() 在第一个项目上,谓词计算结果为 false

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.

别闹i 2025-01-05 06:12:23

All 在第一次不匹配时发生短路,所以这不是问题。

一个微妙的地方是这

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

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

有关此方法的详细信息,请参阅 Enumerable.All 的文档。

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.

一抹微笑 2025-01-05 06:12:23

正如其他答案已经很好地涵盖的那样:这与性能无关,而是与清晰度有关。

您的两种选择都得到了广泛的支持:

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
}

在否定任何内容之前简单地计算布尔值(并命名它)可以在我的脑海中清除很多东西。

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.

木緿 2025-01-05 06:12:23

如果您查看 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;
}

一种方法不可能比另一种方法明显快,因为唯一的区别在于布尔否定,所以更喜欢可读性胜过虚假性能。

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.

岁月无声 2025-01-05 06:12:23

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

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

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

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

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

numbers.All(n => n % 2 == 0); // returns false
numbers.Any(n => n % 2 == 0); // returns true
忆依然 2025-01-05 06:12:23

根据此链接< /a>

任意 - 检查至少一个匹配项

全部 - 检查是否全部匹配

According to this link

Any – Checks for at least one match

All – Checks that all match

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文