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
绝对等同于:
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
变量。