代码之家  ›  专栏  ›  技术社区  ›  luke

linq“let”翻译

  •  27
  • luke  · 技术社区  · 14 年前

    我理解当C编译器看到 linq query comprehension 它基本上直接翻译成相应的LINQ扩展方法和lambda。即

    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 回复  |  直到 7 年前
        1
  •  33
  •   Fyodor Soikin    7 年前

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

    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 关键字是最小化和/或优化查询的一种方法。也就是说,没有 你必须写的关键词:

    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 );
    

    第三 那是什么 非直线运动 关于“块表达式”?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 . 很有用的工具,每个人都应该有一个。

        2
  •  8
  •   Jason Short    14 年前

    看一看 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转换为匿名的temp值,然后在外部select语句中使用。

    我喜欢LinqPad,因为它能够编写查询并查看如何翻译。

        3
  •  0
  •   Kelsey    14 年前

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

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

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

    如果您不想要一个包含v的anon对象,它也可能是如下所示:

    var v = list.Select(x => SomeComplexExpressionDependingOnx(x));
    
        4
  •  -1
  •   Matthew Flaschen    14 年前
    list.Select(x => SomeComplexExpressionDependingOnx );
    

    一般来说, let 基本上是作为 readonly 保持一个范围的变量。