Код, еквівалентний ключовому слову «дозволити» у викликах методу розширення LINQ


192

Використовуючи функції розуміння запиту компіляторів C #, ви можете писати код на зразок:

var names = new string[] { "Dog", "Cat", "Giraffe", "Monkey", "Tortoise" };
var result =
    from animalName in names
    let nameLength = animalName.Length
    where nameLength > 3
    orderby nameLength
    select animalName; 

У виразі запиту вище letключове слово дозволяє передавати значення в операції куди і замовляти без повторних викликів animalName.Length.

Який еквівалентний набір викликів методу розширення LINQ дозволяє досягти того, що робить тут ключове слово "хай"?


11
FYI, специфікація C # 3.0 пояснює кожне правило перекладу розуміння запитів із виразними деталями.
Ерік Ліпперт

17
а для тих, кому здається, що специфікація важка, C # Джона Скіта в глибині також охоплює це
;-p

Специфікації мови C # - це файли Word, які можна завантажити, вміст яких не індексується пошуковими системами і не є ні посиланнями, ні веб-переглядами в Інтернеті. Було б чудово допомогти, якби технічні характеристики були доступні в Інтернеті.
Олів'є Якот-Дескомб

Відповіді:


250

Нехай не має власної роботи; це скарбнички від спини Select. Це можна побачити, якщо ви використовуєте "рефлектор", щоб розбити існуючий dll.

це буде щось на кшталт:

var result = names
        .Select(animalName => new { nameLength = animalName.Length, animalName})
        .Where(x=>x.nameLength > 3)
        .OrderBy(x=>x.nameLength)
        .Select(x=>x.animalName);

4
Woah, я не знав, що ти можеш автокапсулювати за допомогою нового оператора.
Девід Пфеффер

19
Ви також можете використати маленьку кнопку "лямбда" на панелі результатів LinqPad, щоб побачити згенерований код, якщо ви почнете з Queryable. Іншими словами, якщо ви зміните свій перший рядок на var names = new string [] {"Dog", ...} .AsQueryable (); потім запустіть все в LinqPad, натисніть кнопку "лямбда", ви побачите згенерований код практично ідентичний відповіді Марка.
Reb.Cabin

3
Мені потрібно було використовувати .Dump()метод розширення в LinqPad, щоб побачити отриману лямбда.
justagetherdev

88

Там хороша стаття тут

По суті letстворює анонімний кортеж. Це еквівалентно:

var result = names.Select(
  animal => new { animal = animal, nameLength = animal.Length })
.Where(x => x.nameLength > 3)
.OrderBy(y => y.nameLength)
.Select(z => z.animal);

Цитую статтю вищеit seems prudent to recommend against using the let keyword in cases where you do not need to transform a variable
JB. З Монікою.

Цитую це далі:This could be considered a micro-optimisation
Монсеньйор,

7

Існує також метод розширення. Наприклад, розглянемо (у LinqPad, скажімо) наступне вираження, яке створює нові випадкові числа щоразу, коли воно виконується:

var seq = EnumerableEx.Generate(
    new Random(),
    _ => true,
    _ => _,
    x => x.Next());

Щоб побачити, що нові випадкові вибірки з’являються щоразу, врахуйте наступне

seq.Zip(seq, Tuple.Create).Take(3).Dump();

яка виробляє пари, в яких ліва і права відрізняються. Щоб створити пари, в яких лівий і правий завжди однакові, виконайте щось подібне:

seq.Take(3).ToList().Let(xs => xs.Zip(xs, Tuple.Create)).Dump(); 

Якби ми могли безпосередньо викликати лямбда-вирази, ми могли б написати

(xs => xs.Zip(xs, Tuple.Create))(seq.Take(3).ToList()).Dump();

Але ми не можемо викликати лямбда-вирази так, ніби вони були методами.


1

про код, еквівалентний ключовому слову "дозволити" у викликах методу розширення LINQ

вище коментар більше не дійсний

var x = new List<int> { 2, 3, 4, 5, 6 }.AsQueryable();
(from val in x
let val1 = val
let val2 = val + 1
where val2 > val1
select val
).Dump();

виробляє

System.Collections.Generic.List`1[System.Int32]
.Select(
  val =>
     new
     {
         val = val,
         val1 = val
     }
)
.Select(
  temp0 =>
     new
     {
         temp0 = temp0,
         val2 = (temp0.val + 1)
     }
)
.Where(temp1 => (temp1.val2 > temp1.temp0.val1))
.Select(temp1 => temp1.temp0.val)

тому кілька разів letоптимізовано зараз

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.