linq“让”翻译

我理解当C#编译器看到linq查询理解时 ,它基本上直接转换为相应的Linq Extension方法和lambdas。 即

from x in list select x.property 

被翻译成:

 list.Select(x => x.property) 

我的问题是let子句被翻译成什么。 例如,如何由编译器翻译。

 from x in list let v = SomeComplexExpressionDependingOnx select v 

(ps我知道这可以简化为只select SomeComplexExpressionDependingOnx但我想知道这是如何完成的)

谢谢!

在这种特殊情况下,它被转换为:

 list.Select( x => SomeComplexExpressionDependingOnx ); 

但可能会有一个更复杂的情况,例如:

 from x in list let v = SomeComplexExpressionDependingOnx where v > 10 && v+5 < 50 && SomeFunc(v) == "str" select x 

将翻译为:

 list.Where( x => { var v = SomeComplexExpressionDependingOnx; return v > 10 && v+5 < 50 && SomeFunc(v) == "str"; } ) 

换句话说, let关键字是一种最小化和/或优化查询的方法。 也就是说,如果没有let关键字,则必须编写:

 from x in list where SomeComplexExpressionDependingOnx > 10 && SomeComplexExpressionDependingOnx+5 < 50 && SomFunc(SomeComplexExpressionDependingOnx) == "str" select x 

导致可能对同一表达式进行三重评估。

在评论中提出问题后更新

首先 ,对于“块表达式”有什么可怕的? 它们只是任意代表的简写。 也就是说,以下表达式:

 Func f = s => { var ln = s.Length; return ln/2; } 

相当于以下内容:

 int CompilerGeneratedMethodIdentifier0( string s ) { var ln = s.Length; return ln/2; } ... Func f = new Func( CompilerGeneratedMethodIdentifier0 ); 

第二 ,“块表达式”有什么特别之处 ? 你知道mmm ......让我们称它们为“ 非块 ”表达式也扩展到相同的代码吗? 也就是说,简单代码new Func( s => s.Length/2 )绝对等同于:

 int CompilerGeneratedMethodIdentifier0( string s ) { return s.Length/2; } ... new Func( CompilerGeneratedMethodIdentifier0 ); 

第三 ,关于“块表达式”的内容是什么? LINQ在所有地方使用委托,LINQ用于表示这些委托的确切快捷方式并不重要。

特别是, from a in list where a.SomeProp > 10 select new { A = a, B = a.GetB() }表达式将转换为以下内容:

 class AnonymousType0 { public MyClass A { get; set; } public othertype B { get; set; } } bool WhereFunc0( MyClass a ) { return a.SomeProp > 10; } AnonymousType0 SelectResultFunc0( MyClass a ) { AnonymousType0 result = new AnonymousType0(); result.A = a; result.B = a.GetB(); return result; } ... list .Where( new Func( WhereFunc0 ) ) .Select( new Func( SelectResultFunc0 ) ); 

第四 ,为了得到这样的理解,人们可以玩语言和思考。 使用一个人的大脑,就是这样。

第五 ,如果之前的建议因某种原因不适合你,那么你总是有ILSpy 。 非常有用的工具,每个人都应该有一个。

看看LINQPad ,您可以编写查询并点击lamba符号以查看输出结果。 例如,我接受了这个查询:

 var names = new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }.AsQueryable(); var results = from n in names let n1 = String.IsNullOrEmpty(n) select n1; results.Dump(); 

它输出如下:

 System.String[] .Select ( n => new { n = n, n1 = String.IsNullOrEmpty (n) } ) .Select (temp0 => temp0.n1) 

所以看起来确实将let转换为临时值作为匿名,然后在外部select语句中使用。

我喜欢LINQPad能够编写查询并查看它将如何翻译。

只是一个猜测,因为我很少使用查询语法:

 list.Select(x => new { v = SomeComplexExpressionDependingOnx(x) }); 

let只是分配一个新的var v,select正在返回它。

如果你不想要一个带有v的anon对象,它也可能是以下内容:

 var v = list.Select(x => SomeComplexExpressionDependingOnx(x)); 
 list.Select(x => SomeComplexExpressionDependingOnx ); 

通常, let基本上用作保持范围的readonly变量。