2010-06-09 20 views
26

Capisco che quando il compilatore C# vede uno linq query comprehension, fondamentalmente esegue una traduzione diretta ai corrispondenti metodi Linq Extension e lambda. vale a direlinq "let" translation

from x in list 
select x.property 

si traduce a:

list.Select(x => x.property) 

la mia domanda è che cosa fanno let clausole vengono tradotti. per esempio come questo dovrebbe essere tradotto dal compilatore.

from x in list 
let v = SomeComplexExpressionDependingOnx 
select v 

(P.S. so che questo potrebbe essere ridotto a solo select SomeComplexExpressionDependingOnx ma voglio sapere come questo è fatto in generale)

Grazie!

+1

+1 come non avevo usato prima. Informativo. – Kelsey

risposta

33

In questo caso particolare, esso si traduce a:

list.Select(x => SomeComplexExpressionDependingOnx); 

Ma ci può essere un caso più complesso, come ad esempio:

from x in list 
let v = SomeComplexExpressionDependingOnx 
where v > 10 && v+5 < 50 && SomeFunc(v) == "str" 
select x 

si tradurrà in:

list.Where(x => 
    { 
     var v = SomeComplexExpressionDependingOnx; 
     return v > 10 && v+5 < 50 && SomeFunc(v) == "str"; 
    } 
) 

In altre parole, la parola chiave let è un modo per ridurre e/o ottimizzare la query. Cioè, senza la parola chiave let che avrebbe dovuto scrivere:

from x in list 
where 
    SomeComplexExpressionDependingOnx > 10 && 
    SomeComplexExpressionDependingOnx+5 < 50 && 
    SomFunc(SomeComplexExpressionDependingOnx) == "str" 
select x 

Con conseguente possibile la valutazione tripla della stessa espressione.

Aggiornamento, in seguito a una domanda nel commento.

Primo, cosa c'è di così spaventoso riguardo alle "espressioni di blocco"? Sono solo una scorciatoia per delegati arbitrari. Cioè, la seguente espressione:

Func<string,int> f = 
    s => 
    { 
     var ln = s.Length; 
     return ln/2; 
    } 

è equivalente a quanto segue:

int CompilerGeneratedMethodIdentifier0(string s) 
{ 
    var ln = s.Length; 
    return ln/2; 
} 

... 

Func<string, int> f = new Func<string, int>(CompilerGeneratedMethodIdentifier0); 

In secondo luogo, cosa c'è di così speciale su "espressioni di blocco"? Lo sapevi che mmm ...chiamiamoli "non-block" le espressioni si espandono anche nello stesso codice? Cioè, il codice semplice new Func<string,int>(s => s.Length/2) equivale assoluta:

int CompilerGeneratedMethodIdentifier0(string s) 
{ 
    return s.Length/2; 
} 

... 

new Func<string, int>(CompilerGeneratedMethodIdentifier0); 

Terzo, cosa c'è di così non linqy su "espressioni di blocco"? LINQ utilizza i delegati ovunque e non importa a LINQ quale scorciatoia esatta usi per rappresentare quei delegati.

In particolare, la tua espressione from a in list where a.SomeProp > 10 select new { A = a, B = a.GetB() } si traduce in quanto segue:

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

Quarto, per ottenere la comprensione di questo tipo, si può solo giocare con la lingua e pensare. Usa il cervello, cioè.

E quinto, se il consiglio precedente non funziona per te per un motivo o per un altro, hai sempre ILSpy. Strumento molto utile, tutti dovrebbero averne uno.

+0

huh, non mi sarei mai aspettato che si risolvesse in un'espressione di blocco, Block Expressions non mi sembra molto lineare per me. Hai una fonte per questo, o è solo un'ipotesi? – luke

+0

Ho aggiornato la risposta per indirizzare il tuo commento. –

+0

grazie per il duro lavoro, credo che quando ho detto che non pensavo che le espressioni di blocco fossero molto "linq'y", era perché associo (erroneamente) le espressioni di blocco con espressioni che causano effetti collaterali (che sicuramente non è linq'y), ma chiaramente ho sbagliato :). Grazie ancora – luke

0

Solo una supposizione da quando uso raramente sintassi di query:

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

Il let è solo assegnando un nuovo var v il Select è restituirla.

Potrebbe anche essere il seguente se non si desidera che un oggetto anon con v in esso:

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

Wow voti negativi per dare un'esplosione? Almeno postare il motivo per cui non hai votato, non aiuta a informarmi su cosa potrei fare diversamente. – Kelsey

+0

La tua ipotesi è sbagliata. Il codice dell'OP non creerà un tipo anonimo. –

+0

@Matthew Flaschen interessante, se così non fosse, come è valido selezionare v? non 'v' sta memorizzando il risultato di' SomeComplexExpressionDependingOnx'? Non l'ho mai usato prima, quindi poteva essere una cattiva ipotesi, ma mi interessava sapere il perché ora come OP. Suppongo che non sia anonimo poiché 'SomeComplexExpressionDependingOnx' restituirebbe un tipo noto? – Kelsey

-1
list.Select(x => SomeComplexExpressionDependingOnx); 

In generale, let funziona sostanzialmente come una variabile readonly in possesso di un intervallo.

8

Dai uno sguardo allo LINQPad, puoi scrivere la query e premere il simbolo di lamba per vedere come sarà l'output. Per esempio ho preso questa query:

var names = new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }.AsQueryable(); 

var results = 
    from n in names 
    let n1 = String.IsNullOrEmpty(n) 
    select n1; 

results.Dump(); 

Ed è uscita la seguente:

System.String[] 
    .Select (
     n => 
     new 
     { 
      n = n, 
      n1 = String.IsNullOrEmpty (n) 
     } 
    ) 
    .Select (temp0 => temp0.n1) 

Così è effettivamente apparire come let è tradotto in un valore di temperatura come anonimo e quindi consumato nella esterno seleziona la dichiarazione.

Amo LINQPad per la possibilità di scrivere la query e vedere come si tradurrebbe.

+0

Ho pensato che doveva esserci un tipo anonimo o dove sarebbe stata temporaneamente salvata la v ... – Kelsey