LINQ espressione di query traduttore?
-
13-09-2019 - |
Domanda
Sto aggiungendo un'interfaccia LINQ to alcuni oggetti personalizzati, ma il C # compilatore non riesce a inferenza di tipo . Tuttavia, posso scrivere la query equivalente utilizzando i metodi di estensione prime e inferenza di tipo riesce, quindi non sono sicuro di come il compilatore sta traducendo l'espressione di query in chiamate di metodo di estensione.
C'è una bandiera utensile o compilatore così posso vedere quello che il compilatore genera dalla mia espressione di query in modo da questo numero?
Questo codice è in un progetto open source, quindi posso fornire link alla fonte se questo è utile. Lievi variazioni del tipo firme dei metodi di estensione evitare questo errore di inferenza di tipo, ma queste varianti non hanno la semantica che sto cercando.
Soluzione
Il tuo codice di query comprensione è:
from f1 in e1
from f2 in e2
from f3 in e3
select f3
Il tuo codice chiamata del metodo è il seguente:
e1
.SelectMany(f1 => e2)
.SelectMany(f2 => e3), (f2, f3) => f3))
La traduzione interrogazione procede come segue. In primo luogo abbiamo a che fare con i primi due da clausole:
from f1 in e1
from f2 in e2
from f3 in e3
select f3;
Questa è tradotto in
from x in ( e1 ) . SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } )
from f3 in e3
select f3;
dove "X" è un identificatore trasparente. Poiché nessuno di E1, E2 o E3 consumare qualsiasi variabile intervallo, il fatto che questo è un identificatore trasparente è irrilevante; riscrittura nessun ulteriore deve essere fatto per gestire la semantica identificatore trasparenti.
Questo risultato viene poi trasformato in
( ( e1 ) . SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } ) )
.SelectMany( x => e3 , ( x , f3 ) => f3 )
Possiamo eliminare alcune di queste parentesi:
e1
.SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } ) )
.SelectMany( x => e3 , ( x , f3 ) => f3 )
Chiaramente questo è piuttosto diversa dalla trasformazione sintattica che hai fatto manualmente, che, ricordo, è stato
e1
.SelectMany(f1 => e2)
.SelectMany(f2 => e3), (f2, f3) => f3))
Se si sostituisce nella E1, E2, E3 nella trasformazione attuale sintattica sopra, fa il conseguente tipo passa espressione inferenza?
Se non lo fa, allora la domanda è "perché no?" O c'è qualcosa di sbagliato con il codice, o qualcosa che non va con il tipo inferrer. Se c'è qualcosa che non va con il tipo inferrer, fatemelo sapere.
Se è così, allora la domanda è "cosa c'è di sbagliato con il pass trasformazione sintattica"? Se c'è qualcosa di sbagliato con il pass trasformazione sintattica, ancora una volta, me lo faccia sapere.
Grazie!
Altri suggerimenti
È possibile utilizzare riflettore e visualizzare il codice con le ottimizzazioni spenti.
Panoramica di Eric mi ha portato a capire come queste query vengono elaborate. Il problema era che stavo cercando di limitare i tipi di essere operati in modo che la traduzione query non piaceva.
from x in Foo.Bar()
...
Foo.Bar () doveva restituire un futuro e x doveva anche essere di tipo futuro, ma questo non funziona con traduzione query. Ho affrontato questo aggiungendo un altro livello di riferimento indiretto, fondamentalmente avvolgendo future a dire, un Async
public sealed class Async<T> { internal T value; }
public static class Async
{
public static Async<Future<T>> Begin<T>(Future<T> future) { ... }
}
Allora posso scrivere calcoli di query sui valori Async, quindi l'espressione diventa qualcosa di simile a:
from x in Async.Begin(Foo.Bar())
...
dove x è ora di tipo futuro e può forzare o rinviare a termine e promette arbitrariamente.
Grazie per i suggerimenti di tutti. Un traduttore espressione di query integrata in Visual Studio sarebbe bello se, nel caso qualcuno a MS sta leggendo questo. ; -)