Codice equivalente alla parola chiave "let" nelle chiamate al metodo di estensione LINQ concatenate


192

Utilizzando le funzionalità di comprensione delle query dei compilatori C #, è possibile scrivere codice come:

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; 

Nell'espressione di query sopra, la letparola chiave consente di inoltrare un valore alle operazioni where e orderby senza chiamate duplicate a animalName.Length.

Qual è il set equivalente di chiamate al metodo di estensione LINQ che ottiene ciò che fa la parola chiave "let" qui?


11
Cordiali saluti, la specifica C # 3.0 spiega ogni regola di traduzione della comprensione delle query in modo estremamente dettagliato.
Eric Lippert,

17
e per coloro che trovano pesanti le specifiche, anche il C # in Depth di Jon Skeet lo copre ;-p
Marc Gravell

Le specifiche del linguaggio C # sono documenti Word scaricabili il cui contenuto non è indicizzato dai motori di ricerca e non è né collegabile né consultabile online. Sarebbe di grande aiuto se le specifiche fossero disponibili online.
Olivier Jacot-Descombes,

Risposte:


250

Let non ha una propria operazione; si allontana da Select. Puoi vederlo se usi "riflettore" per separare una dll esistente.

sarà qualcosa del tipo:

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, non sapevo che potresti autoincapsulare usando il nuovo operatore in quel modo.
David Pfeffer,

19
Puoi anche usare il piccolo pulsante "lambda" nel riquadro dei risultati di LinqPad per vedere il codice generato se inizi con una query. In altre parole, se cambi la tua prima riga in var names = new string [] {"Dog", ...} .AsQueryable (); quindi esegui tutto in LinqPad, fai clic sul piccolo pulsante lambda, vedrai il codice generato praticamente identico alla risposta di Marc.
Reb.Cabin

3
Avevo bisogno di usare il .Dump()metodo di estensione in LinqPad per vedere il lambda risultante.
justanotherdev,

88

C'è un buon articolo qui

letCrea essenzialmente una tupla anonima. È equivalente a:

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

Cito l'articolo soprait seems prudent to recommend against using the let keyword in cases where you do not need to transform a variable
JB. Con Monica.

Lo cito ulteriormente:This could be considered a micro-optimisation
Mons.

7

Esiste anche un metodo di estensione .Let in System.Interactive, ma il suo scopo è quello di introdurre un'espressione lambda da valutare "in linea" in un'espressione fluente. Ad esempio, considera (in LinqPad, ad esempio) la seguente espressione che crea nuovi numeri casuali ogni volta che viene eseguita:

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

Per vedere che nuovi campioni casuali appaiono ogni volta, considera quanto segue

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

che produce coppie in cui sinistra e destra sono diverse. Per produrre coppie in cui sinistra e destra sono sempre le stesse, fai qualcosa del tipo seguente:

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

Se potessimo invocare direttamente espressioni lambda, potremmo scrivere

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

Ma non possiamo invocare espressioni lambda come se fossero metodi.


1

di Codice equivalente alla parola chiave "let" nelle chiamate del metodo di estensione LINQ concatenate

il commento sopra non è più valido

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

produce

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)

così molti letsono ora ottimizzati

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.