等效于链接的LINQ扩展方法调用中的'let'关键字的代码


191

使用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

什么是LINQ扩展方法调用的等效集合,可以实现此处的“ let”关键字呢?


11
仅供参考,C#3.0规范非常详细地解释了每个查询理解转换规则。
埃里克·利珀特

17
对于那些发现规范不符合要求的人,乔恩·斯基特(Jon Skeet)的C#in Depth也涵盖了该问题;-p
马克·

C#语言规范是可下载的Word文档,其内容不会被搜索引擎索引,也无法在线链接和浏览。如果可以在线获得规格,那将是很大的帮助。
奥利维尔·雅各布·德斯科姆斯

Answers:


249

让我们没有自己的操作;它背负着Select。如果使用“ reflector”将现有的dll分开,则可以看到此信息。

这将是什么样:

var result = names
        .Select(animalName => new { nameLength = animalName.Length, animalName})
        .Where(x=>x.nameLength > 3)
        .OrderBy(x=>x.nameLength)
        .Select(x=>x.animalName);

4
哇,我不知道您可以使用新的运算符来自动封装。
David Pfeffer

19
如果以Queryable开头,您还可以使用LinqPad结果窗格中的小“ lambda”按钮查看生成的代码。换句话说,如果将第一行更改为var names = new string [] {“ Dog”,...} .AsQueryable(); 然后在LinqPad中运行整个程序,单击小lambda按钮,您将看到生成的代码几乎与Marc的答案相同。
Reb.Cabin

3
我需要.Dump()在LinqPad中使用扩展方法来查看生成的lambda。
justanotherdev

88

有一个很好的文章在这里

本质上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
JB。和莫妮卡。

我进一步引用它:This could be considered a micro-optimisation
Monsignor

7

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表达式那样将它们当作方法。


1

关于等效于链接的LINQ扩展方法调用中的“ let”关键字的代码

以上评论不再有效

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现在优化了多个

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.