LINQ to objects'where where子句在幕后做什么?

时间:2009-03-19 22:40:20

标签: c# .net linq performance where-clause

我刚刚更换了这段代码:

foreach( var source in m_sources )
{
    if( !source.IsExhausted )
    {
        ....
    }
}

这一个:

foreach( var source in m_sources.Where( src => !src.IsExhausted ) )
{
   ...
}

现在代码看起来更好(对我而言),但我想知道这里到底发生了什么。我担心这种情况下的性能,如果应用这个过滤器意味着会发生某种编译魔术,那将是个坏消息。

这两段代码基本上是“相同”的吗?是否创建了临时容器来进行过滤,然后将它们传递给我的foreach?

对此主题的任何帮助都将非常感激。感谢。

3 个答案:

答案 0 :(得分:6)

yield return关键字和lambdas确实涉及在编译时创建隐藏类以及在运行时分配额外对象,如果您的背景是C或C ++,那么关注性能是很自然的。

自然,但错了!

I tried measuring the overhead对于关闭局部变量的lambdas,并发现它非常小(几纳秒),几乎在所有应用程序中都没有意义。

答案 1 :(得分:2)

如果是m_sources,则取决于类型。

如果它是从LINQ到SQL或实体框架的数据上下文,则传递的参数将编译为Expression的实例并解析为创建SQL(在数据模型的帮助下)。在这个过程中有一些实际成本,但可能(在大多数情况下)由数据库往返来支配。

如果它是IEnumerable,那么Where实现为:

public static IEnumnerable<T> Where(this IEnumerable<T> input, Func<T, bool> predicate) {
  foreach (var v in input) {
    if (predicate(v)) {
      yield return v;
    }
  }
}

这是非常有效并且懒惰地执行(因此,如果您提前退出循环,谓词将不会应用于整个集合。)

答案 2 :(得分:1)

基本上,是的,它是相同的,O(n)。

当您循环浏览列表时将执行where子句(即,如果您在第一个项目之后中断,则不会测试以下项目。)