编译器会优化与 IEnumerable<T>.Count() 的比较吗?

Will the compiler optimise a comparison against IEnumerable<T>.Count()?

作为一个幼稚的提示,您经常听到使用 IEnumerable.Any() 因为这样就不一定需要遍历整个枚举。

我刚刚写了一小段代码,试图查看 Enumerable 是否包含单个项目或多个项目。

if (reportInfo.OrebodyAndPits.SelectMany(ob => ob.Pits).Count() > 1)
{
    ws.Cells[row, col++].Value = "Pits";
}
else
{
    ws.Cells[row, col++].Value = "Pit";
}

这让我想知道,是否会将比较编译成一种足够智能的形式,以便在枚举超过第一项时立即 return false?

如果没有,有没有办法编写一个 linq 扩展方法来做到这一点?

(请注意,我对这段代码的性能影响不是很感兴趣。我主要是好奇。)

不,不会。您的代码将计算序列中的所有项目。这是因为LINQ语句没有经过编译器优化,所写即所得

检查序列是否包含超过 1 个项目的等效、更有效的方法是:

reportInfo.OrebodyAndPits.SelectMany(ob => ob.Pits).Skip(1).Any();

这将在跳过第一项后检查是否还有剩余项。

如果您想知道某些东西是如何工作的,为什么不查看源代码?

这是 Any() 方法:https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/AnyAll.cs#L20

这里是Count()方法:https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Count.cs#L12

编译器无法像您描述的那样进行优化。它要求计数并获得一个数字,然后将该数字与您的条件语句中的数字进行比较。

不过,它确实尝试进行了某种优化。正如您从 Count() 方法中看到的那样,它会尝试查看 IEnumerable 是否已经支持 Count 属性 并使用它,因为它比再次计算所有元素更快。如果不可用,它必须遍历整个事物并单独计算每个事物。

如果您想编写一个 LINQ 方法(它只是 IEnumerable<T> 上的一个扩展方法)来确定 IEnumerable 中是否至少有两个,那么这应该很容易。像这样:

例如

    public static bool AtLeastTwo<TSource>(this IEnumerable<TSource> source)
    {
        if (source == null)
        {
            throw Error.ArgumentNull(nameof(source));
        }

        using (IEnumerator<TSource> e = source.GetEnumerator())
        {
            e.MoveNext(); // Move past the first one
            return e.MoveNext(); // true if there is at least a second element.
        }
    }