1. ホーム
  2. c#

[解決済み】LINQ:Not Any vs All Don't

2022-03-30 09:18:29

質問

提供された値がリスト内の値と一致するかどうかをチェックしたいことがよくあります (たとえばバリデーションのとき)。

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

最近、ReSharperがこれらのクエリを簡略化するように要求してくるのに気づいた。

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

明らかに、これは論理的に同一で、おそらく(あなたが数学をたくさんやったのなら)よりわずかに読みやすいでしょう。私の質問は、これがパフォーマンスヒットにつながるかどうかということです。

そうすべきな気がします(つまり .Any() は短絡しているように聞こえるのに対し .All() のような気がするのですが、これを証明するものはありません。どなたか、この2つのクエリが同じように解決するのか、あるいはReSharperが私を迷わせるのかについて、深い知識をお持ちの方はいらっしゃいますか?

解決方法は?

の実装 All ILSpyによると(実際に行って見てみると、quot;まあ、その方法はちょっと..."のように動作します。) 私たちが影響ではなく理論を議論している場合、そうするかもしれません。

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-for-objectsだけの話です。他のlinqプロバイダーが一方を他方よりずっと良く扱っている可能性もありますが、もしそうだとしたら、どちらがより最適な実装を得たかはかなりランダムです。

このルールは、ただ単に誰かが if(determineSomethingTrue) よりもシンプルで読みやすい。 if(!determineSomethingFalse) . そして、公平に見て、彼らの言うことも少しはもっともだと思うのですが、私はよく if(!someTest) 同じように冗長で複雑な代替テストがある場合、そのテストが真を返したとき、我々は混乱します。しかし、個人的には、あなたが挙げた2つの選択肢のうち、どちらかを支持するものは何もありませんし、おそらく述語がもっと複雑であれば、ごくわずかに前者に傾くでしょう。

*しかし、私が理解できない決定には何か微妙な理由があるのではないかと心配になり、「いや、彼らはただそのようにすることに決めただけなんだ、ちょっと待って、私は何のためにこのコードのビットを見ていたんだ..."」と気づくのに数回の精神的スキップが必要になるという意味で混乱する。