linq“让”翻译

时间:2010-06-09 01:14:02

标签: c# linq

我理解当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,但我想知道这是如何做的一般)

谢谢!

4 个答案:

答案 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变量。