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

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

最近,我注意到ReSharper要求我将这些查询简化为:
if (acceptedValues.All(v => v != someValue))
{
    // exception logic
}

显然,这在逻辑上是相同的,也许可读性更高(如果您完成了许多数学运算),我的问题是:这会导致性能下降吗?

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

最佳答案

根据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)令人困惑*。但是,实际上,我个人没有发现要比您提供的两种选择中的任何一种更偏爱的,如果谓词更复杂,则可能会略微倾向于前者。

*不要因为我不明白而感到困惑,但是因为担心我不理解的决定有一些微妙的原因而感到困惑,并且需要一些思想上的跳过才能意识到“不,他们只是决定做这样,等我又在看这段代码吗?...”

10-06 08:07