当前位置: 首页 > 编程语言 > C#

LINQ实际上编译成什么?分享

时间:2023-04-10 19:58:56 C#

LINQ实际上编译成什么?背景说到这里的背景是最近在评论里和另一位非常懂行的网友讨论了如何编译LINQ。我先“总结”一下,LINQ编译成for循环。虽然这是不正确的,但我对其他堆栈的理解是LINQ查询被编译为包含循环的lambda。然后在第一次枚举变量时调用它(之后存储结果)。另一位用户表示LINQ需要额外的优化,例如散列。我找不到任何支持或反对这一点的支持文件。我知道这似乎是一个非常模糊的观点,但我一直觉得,如果我根本不了解某些东西是如何工作的,那么我就很难理解为什么我没有正确使用它。问题那么,让我们来看下面这个非常简单的例子:varproductNames=frompinproductswherep.Id>100andp.Id<5000selectp.ProductName;这条语句实际上在CLR中编译了什么?LINQ接管了什么优化只是为了编写一个手动解析结果的函数?这只是语义还是有更多意义?澄清显然我问这个问题是因为我不明白LINQ“黑盒子”的内部是什么样的。虽然我知道LINQ很复杂(而且很强大),但我主要是想了解对CLR或LINQ语句的功能等价物的基本了解。有很多很棒的网站可以帮助理解如何创建LINQ语句,但很少有网站提供有关如何实际编译或运行这些语句的指导。旁注——我肯定读过JohnSkeet关于linq的系列文章。旁注2-我不应该将其标记为LINQtoSQL。我了解ORM和微型ORM的工作原理。这真的是问题的重点。对于LINQtoObjects,它被编译成一组静态方法调用:varproductNames=frompinproductswherep.Id>100andp.Idbecomes:IEnumerableproductNames=products.Where(p=>p.Id>100和p.Idp.ProductName);这使用了Enumerable类型中定义的扩展方法,因此实际上编译为:IEnumerableproductNames=Enumerable.Select(Enumerable.Where(products,p=>p.Id>100andp.Idp.ProductName);handlesthisisconvertedbythecompilertoamethod.将where中的lambda转换为可以设置为Func和可选的Func的方法。请参阅JonSkeet的博客系列:重新实现LINQtoObjects。他将介绍整个过程它有效,包括编译器转换(从查询语法到方法调用)、方法的实现方式等。请注意,LINQtoSql和IQueryable实现是不同的。lambda生成的表达式被传递给查询提供程序,查询提供程序又被传递以某种方式(通过提供者如何做)将其“转换”为调用,通常在服务器上运行ORM。对于这种方法,例如:privatestaticIEnumerableProductNames(IEnumerableproducts){varproductNames=frompinproductswherep.Id>100&&p.Id获取编译为以下IL:.methodprivatehidebysigstaticclass[mscorlib]System.Collections.Generic.IEnumerable`1ProductNames(class[mscorlib]System.Collections.Generic.IEnumerable`1products)cilmanaged{.maxstack3.localsinit([0]class[mscorlib]System.Collections.Generic.IEnumerable`1可枚举,[1]类[mscorlib]System.Collections.Generic.IEnumerable`1可枚举2)L_0000:nopL_0001:ldarg.0L_0002:ldsfld类[mscorlib]System.Func`2ConsoleApplication3.Program::CS$9__CachedAnonymousMethodDelegate3L_0007:dupL_0008:brtrue.sL_001dL_000a:popL_000b:ldnullL_000c:ldftnboolConsoleApplication3.Program::b__2(classConsoleApplication3.Product)L_0012:newobj实例void[mscorlib]System.Func`2::.ctor(object,nativeint)L_0017:dupL_0018:stsfld类[mscorlib]System.Func`2ConsoleApplication3.Program::CS$9__CachedAnonymousMethodDelegate3L_001d:调用类[mscorlib]System.Collections.Generic.IEnumerable`1[System.Core]System.Linq.Enumerable::Where(类[mscorlib]System.Collections.Generic.IEnumerable`1,类[mscorlib]System.Func`2)L_0022:ldsfld类[mscorlib]System.Func`2ConsoleApplication3.Program::CS$9__CachedAnonymousMethodDelegate5L_0027:dupL_0028:brtrue.sL_003dL_002a:popL_002b:ldnullL_002c:ldftnstringConsoleApplication3.Program::b__4(classConsoleApplication3.Product)L_0032:newobj实例void[mscorlib]System.Func`2::.ctor(object,nativeint)L_0037:dupL_0038:stsfldclass[mscorlib]System.Func`2ConsoleApplication3.Program::CS$9__CachedAnonymousMethodDelegate5L_003d:调用类[mscorlib]System.Collections.Generic.IEnumerable`1[System.Core]System.Linq.Enumerable::Select(类[mscorlib]System.Collections.Generic.IEnumerable`1,类[mscorlib]System.Func`2)L_0042:stloc.0L_0043:ldloc.0L_0044:stloc.1L_0045:br.sL_0047L_0047:ldloc.1L_0048:ret}请注意,这些是转换为其他方法的方法调用的正常调用指令lambda,例如:[CompilerGenerated]privatestaticb__2(Productp){return((p.Id>100)&&(p.Id查询语法只是方法语法的语法糖,它有效地编译为:varproductNames=Products().Where(p=>p.Id>100&&p.IdproductName);现在这些函数实际做什么取决于你使用的LINQ的风格,例如LinqtoObjects(将内存中的处理程序链接在一起)或LinqtoSQL(将其转换为SQL查询)等。上面它C#学习教程:LINQ实际编译成什么?所有内容分享,如果对你有用,需要详细了解C#学习教程,希望大家多多关注---本文收藏来自网络,不代表立场,涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: