LINQ 性能

标签 linq

在针对对象集合的 LINQ 查询的幕后究竟发生了什么?它只是语法糖还是发生了其他事情使其更有效的查询?

最佳答案

您是指查询表达式,还是查询在幕后的作用?

查询表达式首先扩展为“普通”C#。例如:

var query = from x in source
            where x.Name == "Fred"
            select x.Age;

被翻译成:
var query = source.Where(x => x.Name == "Fred")
                  .Select(x => x.Age);

这的确切含义取决于 source 的类型。当然...在 LINQ to Objects 中,它通常实现 IEnumerable<T>Enumerable扩展方法开始发挥作用......但它可能是一组不同的扩展方法。 (例如,LINQ to SQL 将使用 Queryable 扩展方法。)

现在,假设我们正在使用 LINQ to Objects... 扩展方法扩展后,上面的代码变为:
var query = Enumerable.Select(Enumerable.Where(source, x => x.Name == "Fred"),
                              x => x.Age);

接下来是 Select 的实现和 Where变得重要。忽略错误检查,它们是这样的:
public static IEnumerable<T> Where<T>(this IEnumerable<T> source,
                                      Func<T, bool> predicate)
{
    foreach (T element in source)
    {
        if (predicate(element))
        {
            yield return element;
        }
    }
}

public static IEnumerable<TResult> Select<TSource, TResult>
    (this IEnumerable<TSource> source,
     Func<TSource, TResult> selector)
{
    foreach (TSource element in source)
    {
        yield return selector(element);
    }
}

接下来是将迭代器 block 扩展为状态机,我不会在这里讨论,但我有一个 article about .

最后,将 lambda 表达式转换为额外的方法 + 适当的委托(delegate)实例创建(或表达式树,取决于所调用方法的签名)。

所以基本上 LINQ 使用了很多 C# 的巧妙特性:
  • Lambda 表达式转换(到委托(delegate)实例和表达式树)
  • 扩展方法
  • 泛型方法的类型推断
  • 迭代器 block
  • 通常是匿名类型(用于投影)
  • 局部变量的隐式类型
  • 查询表达式翻译

  • 然而,单个操作非常简单——它们不执行索引等。连接和分组是使用哈希表完成的,但是像“where”这样的简单查询只是线性的。不要忘记 LINQ to Objects 通常只是将数据视为只能向前读取的序列——它不能执行二进制搜索之类的操作。

    通常我希望手写查询比 LINQ to Objects 稍微快一点,因为抽象层更少,但它们的可读性会降低,而且性能差异通常不会很大。

    与以往一样,对于性能问题:如有疑问,请测量!

    关于LINQ 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1229838/

    相关文章:

    c# - 最后用空值排序

    javascript - 如何在 Razor 的 LINQ 表达式中嵌入 JavaScript?

    c# - 提高 linq 查询的性能

    c# - 在C#中读取csv文件

    c# - Linq 是否提供了一种轻松发现序列中间隙的方法?

    c# - 从 IEnumerable<IEnumerable<object>> linq 选择 IEnumerable<object>

    c# - 在树层次结构中查找给定子 LINQ(lambda 表达式)的父级

    c# - 如何合并拆分为 2 个具有奇数和偶数索引的数组?

    c# - linq where 子句中的空值

    c# - 获得最多数组的Linq解决方案