C# LINQ序列-它们在IL中是如何链接的?
无论我使用表达式查询语法还是方法语法,IL看起来几乎相同 以“渐进式语法”执行LINQ查询:C# LINQ序列-它们在IL中是如何链接的?,c#,linq,C#,Linq,无论我使用表达式查询语法还是方法语法,IL看起来几乎相同 以“渐进式语法”执行LINQ查询: IEnumerable<Employee> query1 = _employees.Where(e => e.Location.Equals("California")); IEnumerable<Employee> query2 = query1.OrderByDescending(e => e.Name); IEnumerable<string> qu
IEnumerable<Employee> query1 = _employees.Where(e => e.Location.Equals("California"));
IEnumerable<Employee> query2 = query1.OrderByDescending(e => e.Name);
IEnumerable<string> query3 = query2.Select(e => e.Name);
如果我以“流畅”的方式执行LINQ查询:
IEnumerable<string> names = _employees.Where(e => e.Location.Equals("California")).OrderByDescending(e => e.Name).Select(e => e.Name);
IEnumerable Name=\u employees.Where(e=>e.Location.Equals(“加利福尼亚”)).OrderByDescending(e=>e.Name)。选择(e=>e.Name);
我没有得到stloc.0、ldloc.0指令。这是“渐进语法”和“流畅语法”之间的唯一区别。JIT编译器中是否还有第二步生成额外的IL指令来进行序列输入?两个版本之间的唯一区别是局部变量。在第一个版本中,每个调用的返回值都保存到本地,然后对该本地调用下一个方法,依此类推 我想你要问的是,在没有当地人的情况下,它是如何工作的?方法的返回值存储在哪里 它存储在计算堆栈中。然后使用求值堆栈中的值调用下一个方法。在链中调用最后一个方法后,结果被设置回局部变量
names
查看说明,逐步了解其工作原理:
\u employees
推到堆栈上,将Func
推到堆栈上Where
本地0
local 0
(将其推到堆栈上),将Func
推到堆栈上OrderByDescending
本地1
local 1
,将Func
推到堆栈上选择
local2
注意:我简化了推送委托步骤,额外的代码用于缓存。在创建新的委托实例之前,委托实例缓存在编译器生成的类字段中。编译器会检查是否在创建委托实例之前进行了效率检查。在“渐进语法”和“流畅语法”之间的唯一区别是,在第一种情况下,您有一堆局部变量
stloc.0
和ldloc.0
用于写入和读取它们。查看特定行:IL_004a:call class[System.Core]System.Linq.iorderenumerable1[System.Core]System.Linq.Enumerable::OrderByDescending(class[mscorlib]System.Collections.Generic.IEnumerable
1,class[mscorlib]System.Func`2)第一个参数是输入序列(Where操作的输出序列),它是什么!!0? 我感觉这就是实际的集合。@Alex.A我想它们指的是泛型类型参数。所以在这个调用中:System.Linq.Enumerable::Select
!!0
表示员工
和!!1
表示字符串
。你说得对。我只是想确定表示输入序列的IL代码的确切部分。是IL_0035:pop吗?@Alex.A否,输入序列在调用后被推送到堆栈中,没有单独的指令将其推送到堆栈中。的结果,其中
成为OrderByDescending
@Alex的输入。A从IL_0053开始直到调用指令(IL_0072)用于缓存的代码,我在注释中解释了它。它所做的只是将第二个参数(委托)推送到堆栈中。
IL_002b: stloc.0 // query1
// [100 13 - 100 82]
IL_002c: ldloc.0 // query1
IEnumerable<string> names = _employees.Where(e => e.Location.Equals("California")).OrderByDescending(e => e.Name).Select(e => e.Name);