我理解当C#编译器看到linq query comprehension时,它基本上直接转换为相应的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
(p.s。我知道这可以简化为select SomeComplexExpressionDependingOnx
,但我想知道这是如何做的一般)
谢谢!
答案 0 :(得分:33)
在这种特殊情况下,它被翻译为:
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<string,int> f =
s =>
{
var ln = s.Length;
return ln/2;
}
等同于以下内容:
int CompilerGeneratedMethodIdentifier0( string s )
{
var ln = s.Length;
return ln/2;
}
...
Func<string, int> f = new Func<string, int>( CompilerGeneratedMethodIdentifier0 );
第二次,关于“块表达式”的特殊是什么?你知道吗......我们称他们为“非阻止”表达式也扩展为相同的代码吗?也就是说,简单代码new Func<string,int>( s => s.Length/2 )
绝对等同于:
int CompilerGeneratedMethodIdentifier0( string s )
{
return s.Length/2;
}
...
new Func<string, int>( CompilerGeneratedMethodIdentifier0 );
第三次,关于“块表达式”的非linqy 是什么? 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<MyClass,bool>( WhereFunc0 ) )
.Select( new Func<MyClass,AnonymousType0>( SelectResultFunc0 ) );
第四,为了得到这样的理解,人们可以玩语言并思考。使用一个人的大脑,就是这样。
第五次,如果之前的建议因某种原因不适合您,则您总是ILSpy。非常有用的工具,每个人都应该有一个。
答案 1 :(得分:8)
看看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,因为它能够编写查询并查看它是如何翻译的。
答案 2 :(得分:0)
因为我很少使用查询语法而只是猜测:
list.Select(x => new { v = SomeComplexExpressionDependingOnx(x) });
let只是分配一个新的var v,select正在返回它。
如果您不想要带有v的anon对象,也可以是以下内容:
var v = list.Select(x => SomeComplexExpressionDependingOnx(x));
答案 3 :(得分:-1)
list.Select(x => SomeComplexExpressionDependingOnx );
通常,let
基本上用作保存范围的readonly
变量。