c# student LINQ:沒有任何與所有沒有




resharper教學 (7)

正如其他答案所涵蓋的:這不是關於表現,而是關於清晰度。

對您的兩種選擇都有廣泛的支持:

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
}

在否定任何事情之前簡單地計算布爾值(並命名它)會讓我想起很多事情。

通常我想檢查提供的值是否與列表中的值匹配(例如,驗證時):

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

最近,我注意到ReSharper要求我簡化這些查詢:

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

顯然,這在邏輯上是相同的,也許稍微有點可讀性(如果你已經做了很多數學),我的問題是:這是否會導致性能下降?

它感覺應該是這樣的(即.Any()聽起來像是短路,而.All()聽起來好像不是),但我沒有任何證據證實這一點。 有沒有人有更深入的了解,這些問題是否會解決相同的問題,或者ReSharper是否讓我誤入歧途?


如果你看一下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;
}

沒有辦法,一種方法比另一種方法明顯更快,因為唯一的區別在於布爾否定,所以偏好可讀性勝過虛假表現。


根據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提供者對待一個比另一個更好,但是如果是這樣的話,那麼隨機哪一個獲得更優化的實現是非常隨機的。

看起來規則只能歸結為某人感覺if(determineSomethingTrue)if(!determineSomethingFalse)更簡單並且更具可讀性。 公平地說,我認為他們有一點是我經常發現if(!someTest)令人困惑的時候*當有一個相同冗長和復雜性的替代測試時,如果我們想要採取行動的條件會返回true。 但是,實際上,我個人發現沒有什麼比這兩種選擇中的另一種更受青睞,如果謂詞比較複雜的話,它可能會對前者略微傾斜。

*不會混淆,因為我不明白,但是令人困惑的是,我擔心這個決定有一些細微的原因,我不明白,而且需要一些心理跳躍才能認識到“不,他們只是決定去做那麼,等等,我再看看這段代碼是什麼?......“


All()確定序列的所有元素是否滿足條件。
Any()確定序列中的任何元素是否滿足條件。

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

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

根據這個link

任何 - 檢查至少一場比賽

全部 - 全部匹配


您可能會發現這些擴展方法使您的代碼更具可讀性:

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





resharper