LINQ实际上编译成什么?

2023-11-24

背景

其背景是我最近在评论中与另一位显然知识渊博的用户就 LINQ 的编译方式进行了对话。我先“总结”一下,说LINQ被编译成for循环。虽然这是不正确的,但我对其他堆栈的理解,例如this one是 LINQ 查询被编译为内部有循环的 lambda。然后在第一次枚举变量时调用此函数(之后存储结果)。另一位用户表示 LINQ 进行了额外的优化,例如散列。我找不到任何支持或反对这一点的支持文档。

我知道这似乎是一个非常晦涩的观点,但我一直觉得,如果我不完全理解某些东西是如何工作的,就很难理解为什么我没有正确使用它。

问题

那么,让我们看下面这个非常简单的例子:

var productNames = 
    from p in products 
    where p.Id > 100 and p.Id < 5000
    select p.ProductName;

这是什么声明actually编译到CLR中? LINQ 对我仅编写一个手动解析结果的函数进行了哪些优化?这只是语义还是还有更多内容?

澄清

显然我问这个问题是因为我不明白 LINQ“黑匣子”的内部是什么样的。尽管我知道 LINQ 很复杂(而且功能强大),但我主要是在寻求对 CLR 或与 LINQ 语句等效的功能的基本了解。有很多很棒的网站可以帮助您了解如何创建 LINQ 语句,但其中很少有网站提供有关如何实际编译或运行这些语句的任何指导。

边注- 我绝对会通读 John Skeet 有关 linq to object 的系列文章。

旁注 2- 我不应该将其标记为 LINQ to SQL。我了解 ORM 和微型 ORM 的工作原理。这确实超出了问题的重点。


对于 LINQ to Objects,这被编译为一组静态方法调用:

var productNames = 
    from p in products 
    where p.Id > 100 and p.Id < 5000
    select p.ProductName;

Becomes:

IEnumerable<string> productNames = products
                                       .Where(p => p.Id > 100 and p.Id < 5000)
                                       .Select(p => p.ProductName);

这使用了中定义的扩展方法Enumerable类型,所以实际上编译为:

IEnumerable<string> productNames = 
     Enumerable.Select(
        Enumerable.Where(products, p => p.Id > 100 and p.Id < 5000),
        p => p.ProductName
     );

处理此问题的 lambda 表达式由编译器转换为方法。 where 中的 lambda 变成了一个可以设置为 a 的方法Func<Product, Boolean>,然后选择进入Func<Product, String>.

有关详细说明,请参阅Jon Skeet 的博客系列:重新实现 LINQ to Objects。他详细介绍了其工作原理的整个过程,包括编译器转换(从查询语法到方法调用)、方法的实现方式等。

请注意,LINQ to Sql 和IQueryable<T>实现方式不同。这Expression<T>由 lambda 生成的数据被传递到查询提供程序,查询提供程序又以某种方式(由提供程序决定如何执行此操作)“转换”为调用,通常在 ORM 的情况下在服务器上运行。


对于该方法,例如:

    private static IEnumerable<string> ProductNames(IEnumerable<Product> products)
    {
        var productNames =
            from p in products
            where p.Id > 100 && p.Id < 5000
            select p.ProductName;
        return productNames;
    }

编译为以下 IL:

  .method private hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<string> ProductNames(class [mscorlib]System.Collections.Generic.IEnumerable`1<class ConsoleApplication3.Product> products) cil managed
{
    .maxstack 3
    .locals init (
        [0] class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable,
        [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable2)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, bool> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate3
    L_0007: dup 
    L_0008: brtrue.s L_001d
    L_000a: pop 
    L_000b: ldnull 
    L_000c: ldftn bool ConsoleApplication3.Program::<ProductNames>b__2(class ConsoleApplication3.Product)
    L_0012: newobj instance void [mscorlib]System.Func`2<class ConsoleApplication3.Product, bool>::.ctor(object, native int)
    L_0017: dup 
    L_0018: stsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, bool> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate3
    L_001d: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<class ConsoleApplication3.Product>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
    L_0022: ldsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, string> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate5
    L_0027: dup 
    L_0028: brtrue.s L_003d
    L_002a: pop 
    L_002b: ldnull 
    L_002c: ldftn string ConsoleApplication3.Program::<ProductNames>b__4(class ConsoleApplication3.Product)
    L_0032: newobj instance void [mscorlib]System.Func`2<class ConsoleApplication3.Product, string>::.ctor(object, native int)
    L_0037: dup 
    L_0038: stsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, string> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate5
    L_003d: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!1> [System.Core]System.Linq.Enumerable::Select<class ConsoleApplication3.Product, string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>)
    L_0042: stloc.0 
    L_0043: ldloc.0 
    L_0044: stloc.1 
    L_0045: br.s L_0047
    L_0047: ldloc.1 
    L_0048: ret 
}

注意这些都是正常的call方法调用的说明。 lambda 被转换为其他方法,例如:

[CompilerGenerated]
private static bool <ProductNames>b__2(Product p)
{
    return ((p.Id > 100) && (p.Id < 0x1388));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LINQ实际上编译成什么? 的相关文章

  • 如何在特定时间以毫秒精度触发 C# 函数?

    我有两台计算机 它们的时间通过 NTP 同步 确保时间仅相差几毫秒 其中一台计算机将通过 TCP 向另一台计算机发送一条消息 以在两台计算机上的未来指定时间启动某个 c 函数 我的问题是 如何在特定时间以毫秒精度 或更好 触发 C 中的函数
  • ASP.NET Web 应用程序中的身份验证遇到问题

    我正在尝试对从登录页面登录我的 Web 应用程序的用户进行身份验证 我正在使用本教程 http support microsoft com kb 301240作为指南 它几乎准确地解释了我希望做什么 但是当我输入用户名和密码时 验证不起作用
  • 深拷贝和动态转换 unique_ptr

    假设我有一个如下所示的类 class A virtual A class B public A class C public A 我还有一个 unique ptr 向量 它是这样声明的 std vector
  • 平滑手绘曲线

    我有一个允许用户绘制曲线的程序 但这些曲线看起来不太好 它们看起来摇摇欲坠 而且是手绘的 所以我想要一种能够自动平滑它们的算法 我知道平滑过程中存在固有的模糊性 因此它不会每次都完美 但这种算法似乎确实存在于多个绘图包中 并且它们工作得很好
  • 局部函数声明有什么用处吗?

    大多数像我这样的 C 程序员都曾犯过以下错误 class C int main C c declares a function c taking no arguments returning a C not as intended by m
  • 对作为函数参数传递的指针使用删除

    删除作为函数参数传递的指针是否可以 并且合法 如下所示 include
  • 如何减少 MinGW g++ 编译器生成的可执行文件的大小?

    我有一个简单的 Hello world C 程序 在 Win XP 下由 MinGW g 编译器编译为 500kB 可执行文件 有人说这是由于iostream的库和静态链接libstdc dll Using s链接器选项有点帮助 减少了 5
  • C# 枚举到字符串自动转换?

    是否可以让编译器自动将我的 Enum 值转换为字符串 这样我就可以避免每次都显式调用 ToString 方法 这是我想做的一个例子 enum Rank A B C Rank myRank Rank A string myString Ran
  • 如何将STL容器数据转储到gdb中?

    我无法在 gdb 中转储 STL 无序映射容器值 变量类型是 std unordered map var 我的 gdb 版本 7 7 1 GDB配置 configure host x86 64 linux gnu target x86 64
  • 处理“未找到细胞”。 Excel 中的错误

    我正在使用 Excel VSTO 应用程序并使用以下代码在工作表中查找错误单元格 Excel Range rngTemp Excel Range rngErrorRange Excel Worksheet Sheet1 Excel Work
  • 我可以将 UseCSharpNullComparisonBehavior 用于单个查询吗?

    我有一个查询 该查询曾经是存储过程 现已转换为 EF 查询 现在已经超时了 使用 SQL Profiler 我可以看到生成的 SQL 的唯一区别是 EF 转变的新行为entity Property value into entity Pro
  • 配置:错误:无法运行C编译的程序

    我正在尝试使用 Debian Wheezy 操作系统在我的 Raspberry Pi 上安装不同的软件 当我运行尝试配置软件时 我尝试安装我得到此输出 checking for C compiler default output file
  • 如何构建一棵与或树?

    我需要一个支持 与 和 或 的树结构 例如 给定一个正则表达式 如ab c d e 我想把它变成一棵树 所以 一开始我们有两个 或 分支 它可以向下ab or c d e 如果你低头ab分支 你得到两个节点 a and b or a其次是b
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • 传递数组时在 C 中的函数参数中强制指定数组大小

    Context 在 C 中 我有一个以数组作为参数的函数 该参数用作该函数的输出 输出的大小始终相同 我会 让阅读代码的人清楚所需的大小 不过它已经在函数注释中了 理想情况下 编译会输出警告或错误 这样我就可以在编译时而不是运行时防止出现问
  • Gremlin.net 文本包含等效项

    我正在使用 Gremlin net 库连接到 janus 图形服务器 我使用 cassandra 和弹性搜索进行数据存储和索引 在我使用的 gremlin 语言和 gremlin 控制台中文本包含在属性的文本中进行搜索 我正在使用混合索引
  • 从对列表创建邻接列表类型结构

    在 C 中 我有 class Pair int val1 int val2 我有一个来自以下来源的配对列表 List
  • 实体框架代码首次日期字段创建

    我正在使用实体框架代码优先方法来创建我的数据库表 下面的代码 创建一个DATETIME数据库中的列 但我想创建一个DATE柱子 DataType DataType Date DisplayFormatAttribute ApplyForma
  • 将一个 IEnumerable 拆分为多个 IEnumerable

    我是 linq 新手 我需要根据指示器将 Couple string text bool Indicator 类型的 IEnumerable 拆分为多个 IEnumerable 我尝试使用skipWhile 和 TakeWhile 但没有找
  • 如何使用 C# 为 azure devops 变量赋值

    我有 selenium C 测试脚本 可以从浏览器获取令牌 我有两个 azure devops 任务 一个用于执行 selenium 测试 另一个用于执行 API 测试 我想将 selenium 测试获取的令牌传递给 API 测试执行任务

随机推荐

  • AttributeError:模块“os”没有属性“uname”

    当我做 gt gt gt import os gt gt gt os uname 我收到一个属性错误 如下所示 Traceback most recent call last File
  • 如何处理python请求中的401(未经授权)

    我想要做的是从站点获取 如果该请求返回 401 则重做我的身份验证摆动 可能已过时 并重试 但我不想尝试第三次 因为那将是我的身份验证摇摆不定的凭证 有没有人有一个很好的方法来做到这一点 并且不涉及丑陋的代码 最好是在 python req
  • Python:Xlib——如何升起(置顶)窗口?

    我尝试过使用 win configure stack mode X TopIf win set input focus X RevertToParent X CurrentTime 然而 即使我的窗口管理器上没有任何焦点丢失预防措施 这也不
  • 是否可以在ios 9中获取wifi信号强度

    我想检查 WIFI 信号强度 以便在 WIFI 信号弱时显示某种消息 我发现在 iOS 8 及更早版本中这是不可能的 iOS 9 中可以获取 wifi 信号强度吗 如果答案是肯定的那么如何 是的 在 iOS 9 中是可能的 查看一下NE热点
  • Oreo 版本问题不支持此图像的编辑

    Oreo 版本问题中的此图像不支持编辑 此图像不支持编辑 当从 Oreo 版本移动设备中的图库中选择图像时 会显示此 Toast 我已经问过这个问题了 但没有人回复我 请检查我的代码并尽快恢复 这是我的代码 Override public
  • 使用 pyinotify 监视文件创建,但等待它完全写入磁盘

    我正在使用 pyinotify 来监视文件夹中何时创建文件 当创建某些文件时 我想移动它们 问题是 一旦创建文件 显然 我的程序就会尝试移动它 甚至在它完全写入磁盘之前 有没有办法让 pyinotify 等到文件完全写入磁盘后再通知我它已创
  • CSS 在 Chrome 中不起作用

    我正在处理的网站的此页面未加载 CSS http www thesanfordcenter net sanford center 它只发生在 Chrome 中 但不是缓存问题 因为同样的问题也发生在另一台计算机上的 Chrome 中 并且我
  • 将隐式 ExecutionContext 传递给包含的对象/调用的方法

    我正在使用 Scala 2 10 futures 创建一个异步库 库的构造函数采用一系列实现特定特征的用户定义对象 然后库类上的方法将一些数据逐一发送到用户定义的对象中 我希望用户提供ExecutionContext用于设置主实例时的异步操
  • LINQ/Lambda 相当于 SQL

    我有一个 IEnumerable 其中包含带有 id 的对象列表 我想选择那些 ID 为 1 2 7 8 9 10 和 11 的对象 我不知道等效 SQL 语句的 LINQ Lambda 等效项 select where id in 1 2
  • 从 WebView 启动自定义 Android 应用程序

    我有一个 HTML 文件 如果我在 Android 本机浏览器中打开它 它就会启动一个应用程序 但是当我尝试在 WebView 中打开相同的应用程序时 它无法启动该应用程序 并且显示 网页不可用 我认为我的 WebView 无法处理为应用程
  • JSF、RichFaces、分页

    我知道这里有很多关于 JSF 分页的帖子 但没有一个让我满意 为了将相当大的数据分割成页面 我将使用 RichFaces 数据滚动器组件 它似乎适合于此 但看起来它是 人工 分页的 我不喜欢这里的是它加载所有数据 然后只显示其中的一部分 至
  • 动态解析逻辑运算 - AND、OR、循环条件

    我有一个传入记录过滤器 存储有逻辑子句 如下所示 Acct1 Y AND Acct2 N AND Acct3 N AND Acct4 N AND Acct5 N AND Acct6 N OR Acct7 N AND Acct1 Y AND
  • f() 和 (f()) 之间有什么区别吗?

    之间有任何区别 var myfunc function return function and var myfunc function return function 这只是风格问题还是第一种形式中的 周围还有更多内容 没有 或者至少在你的
  • 透明背景与 Three.js

    代码有效 但我在使用 Three js 设置画布透明背景时遇到问题 我用 Background renderer setClearColor 0xffffff 0 但随后背景变黑 如何将其更改为透明 代码 var camera scene
  • 如何使用 argparse 创建“对列表”类型的参数?

    我需要让 python 脚本的最终用户输入如下内容 script py sizes lt 2 2 gt lt 3 3 gt lt 6 6 gt 其中的每个元素 sizes选项是一对两个正整数 我怎样才能做到这一点argparse 定义自定义
  • 如何配置 Squirrel SQL 客户端以与 MS Access 一起使用

    我正在努力让 Squirrel SQL 连接到 MS Access 数据库 只是一个普通的数据库 没有密码 我创建一个别名并使用驱动程序 JBDC ODBC 桥 此驱动程序前面有一个勾 我不知道在网址中输入什么 我使用 数据库文件路径 gt
  • 使 GWT 应用程序可由搜索引擎抓取

    我想使用 使我的 GWT 应用程序可爬网的令牌 如下所述 http code google com web ajaxcrawling 在线有一个使用此功能的 GWT 示例应用程序 例如 http gwt google com samples
  • 连接 std::variant 和 std::variant 的类型

    有没有办法从两个现有变体类型声明第三个变体 其中包含两个变体类型的并集 include
  • UIDocument 和 NSFileWrapper 架构和性能

    我们最近将代码转换为使用 UIDocument 而不是直接操作文件系统上的文件 因此我们遇到了一些性能问题 我们想知道我们是否错误地使用了这个类 是否有其他人遇到这些问题 以及解决这些问题的常见方法是什么 Our app 我们有一个 鞋盒应
  • LINQ实际上编译成什么?

    背景 其背景是我最近在评论中与另一位显然知识渊博的用户就 LINQ 的编译方式进行了对话 我先 总结 一下 说LINQ被编译成for循环 虽然这是不正确的 但我对其他堆栈的理解 例如this one是 LINQ 查询被编译为内部有循环的 l