等效于链式 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' 关键字的代码的主要内容,如果未能解决你的问题,请参考以下文章

用于LINQ的SQL等效扩展方法并不明显

等效于“Into”的Linq方法[重复]

Java 等效于 C# Linq 中的 Where 子句

.NET深入解析LINQ框架(五:IQueryableIQueryProvider接口详解)

JavaScript 等效于 jQuery 的扩展方法

PHP(或其他 linux 友好)等效于 .Net System.Xml.Linq