Подтвердить что ты не робот

Linq "let" перевод

Я понимаю, что когда компилятор С# видит понимание 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

(p.s. Я знаю, что это можно свести только к select SomeComplexExpressionDependingOnx, но я хочу знать, как это делается вообще)

Спасибо!

4b9b3361

Ответ 1

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

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

Второй, что особенно важно в отношении "блочных выражений"? Знаете ли вы, что mmm... пусть их называют "неблокирующими" выражениями, также распространяются на тот же самый код? То есть простой код 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. Очень полезный инструмент, каждый должен иметь его.

Ответ 2

Взгляните на 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

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

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

Позвольте просто назначить новый var v, который выбирает, возвращает его.

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

var v = list.Select(x => SomeComplexExpressionDependingOnx(x));

Ответ 4

list.Select(x => SomeComplexExpressionDependingOnx );

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