等效于链式 LINQ 扩展方法调用中的 'let' 关键字的代码
Posted
技术标签:
【中文标题】等效于链式 LINQ 扩展方法调用中的 \'let\' 关键字的代码【英文标题】:Code equivalent to the 'let' keyword in chained LINQ extension method calls等效于链式 LINQ 扩展方法调用中的 'let' 关键字的代码 【发布时间】:2010-11-08 17:25:12 【问题描述】:使用 C# 编译器的查询理解功能,您可以编写如下代码:
var names = new string[] "Dog", "Cat", "Giraffe", "Monkey", "Tortoise" ;
var result =
from animalName in names
let nameLength = animalName.Length
where nameLength > 3
orderby nameLength
select animalName;
在上面的查询表达式中,let
关键字允许将值转发给 where 和 orderby 操作,而不会重复调用 animalName.Length
。
实现“let”关键字在这里的作用的等效 LINQ 扩展方法调用集是什么?
【问题讨论】:
仅供参考,C# 3.0 规范详细解释了每个查询理解翻译规则。 对于那些觉得规范很繁重的人,Jon Skeet 的 C# in Depth 也涵盖了它;-p C# 语言规范是可下载的 Word 文档,其内容未被搜索引擎索引,既不能链接也不能在线浏览。如果这些规范可以在线获得,那将是一个很大的帮助。 【参考方案1】:关于Code equivalent to the 'let' keyword in chained LINQ extension method calls
以上评论不再有效
var x = new List<int> 2, 3, 4, 5, 6 .AsQueryable();
(from val in x
let val1 = val
let val2 = val + 1
where val2 > val1
select val
).Dump();
产生
System.Collections.Generic.List`1[System.Int32]
.Select(
val =>
new
val = val,
val1 = val
)
.Select(
temp0 =>
new
temp0 = temp0,
val2 = (temp0.val + 1)
)
.Where(temp1 => (temp1.val2 > temp1.temp0.val1))
.Select(temp1 => temp1.temp0.val)
现在优化了多个let
【讨论】:
【参考方案2】:有一篇好文章here
基本上let
创建一个匿名元组。相当于:
var result = names.Select(
animal => new animal = animal, nameLength = animal.Length )
.Where(x => x.nameLength > 3)
.OrderBy(y => y.nameLength)
.Select(z => z.animal);
【讨论】:
我引用上面的文章it seems prudent to recommend against using the let keyword in cases where you do not need to transform a variable
我进一步引用它:This could be considered a micro-optimisation
【参考方案3】:
System.Interactive 中还有一个 .Let 扩展方法,但它的目的是引入一个 lambda 表达式,以便在流畅的表达式中“内联”求值。例如,考虑(例如在 LinqPad 中)以下表达式,它每次执行时都会创建新的随机数:
var seq = EnumerableEx.Generate(
new Random(),
_ => true,
_ => _,
x => x.Next());
要查看每次都出现新的随机样本,请考虑以下事项
seq.Zip(seq, Tuple.Create).Take(3).Dump();
生成左右不同的对。要生成左右始终相同的对,请执行以下操作:
seq.Take(3).ToList().Let(xs => xs.Zip(xs, Tuple.Create)).Dump();
如果我们可以直接调用 lambda 表达式,我们可以写
(xs => xs.Zip(xs, Tuple.Create))(seq.Take(3).ToList()).Dump();
但我们不能像调用方法一样调用 lambda 表达式。
【讨论】:
【参考方案4】:Let 没有自己的操作;它搭载了Select
。如果您使用“反射器”拆分现有的 dll,您可以看到这一点。
它会是 一些东西,比如:
var result = names
.Select(animalName => new nameLength = animalName.Length, animalName)
.Where(x=>x.nameLength > 3)
.OrderBy(x=>x.nameLength)
.Select(x=>x.animalName);
【讨论】:
哇,我不知道你可以像这样使用 new 运算符自动封装。 您还可以使用 LinqPad 结果窗格中的小“lambda”按钮查看生成的代码如果您以 Queryable 开头。换句话说,如果您将第一行更改为 var names = new string [] "Dog", ... .AsQueryable();然后在 LinqPad 中运行整个程序,单击小 lambda 按钮,您将看到生成的代码与 Marc 的答案几乎相同。 我需要在 LinqPad 中使用.Dump()
扩展方法来查看生成的 lambda。以上是关于等效于链式 LINQ 扩展方法调用中的 'let' 关键字的代码的主要内容,如果未能解决你的问题,请参考以下文章