linq “позволяют” переводу

Я понимаю, что, когда компилятор C# видит понимание запроса linq, он в основном делает прямой перевод в соответствующие Дополнительные методы Linq и лямбды. т.е.

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 но я хочу знать, как это сделано в целом),

Спасибо!

27
задан luke 9 June 2010 в 01:14
поделиться

4 ответа

В данном конкретном случае он переводится в:

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( 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. Очень полезный инструмент, он должен быть у каждого.

33
ответ дан 28 November 2019 в 05:26
поделиться

Просто предположение, поскольку я редко использую синтаксис запроса:

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

let просто назначает новую переменную v, а select возвращает ее.

Это также может быть следующее, если вы не хотите анонимный объект с v в нем:

var v = list.Select(x => SomeComplexExpressionDependingOnx(x));
0
ответ дан 28 November 2019 в 05:26
поделиться
list.Select(x => SomeComplexExpressionDependingOnx );

В общем, let в основном работает как readonly переменная, хранящая диапазон.

-1
ответ дан 28 November 2019 в 05:26
поделиться

Взгляните на LINQPad , вы можете написать запрос и нажать на символ ламбы, чтобы увидеть, как будет выглядеть результат. Например, я взял этот запрос:

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 за возможность писать запросы и смотреть, как они будут переведены.

8
ответ дан 28 November 2019 в 05:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: