编译器是否会优化与IEnumerable <t> .Count()的比较?

时间:2016-11-28 07:49:38

标签: c# linq csc

作为一个天真的提示,你经常听到使用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";
}

这让我想知道,比较是否会编译成一个足够聪明的形式,一旦枚举超过第一个项目就会返回false?

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

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

2 个答案:

答案 0 :(得分:4)

不,它不会。您的代码将计算序列中的所有项目。这是因为编译器没有对LINQ语句进行优化,你所写的是你得到的。

检查序列是否包含多于1个项目的公平,更有效的方法是:

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

这将在跳过第一个项目后检查是否还有任何项目。

答案 1 :(得分:3)

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

以下是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中是否至少有两个,那么这应该很容易。像这样:

e.g。

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