2011-11-14 3 views
24

Sto cercando di capire AST in C#. Mi chiedo, che cosa fa esattamente il metodo Compile() da questo esempio.Cosa fa il metodo Lambda Expression Compile()?

// Some code skipped  
Expression<Func<string, int, int, string>> data = Expression.Lambda<Func<string, int, int, string>>( 
     Expression.Call(s, typeof(string).GetMethod(“Substring”, new Type[] { typeof(int), typeof(int) }), a, b), 
     s, a, b 
    ); 
Func<string, int, int, string> fun = data.Compile(); 

Per evitare equivoci, ho capito il Expression.Lambda e Expression.Call costrutti. Quello che mi interessa è il metodo Compile(). In qualche modo produce vero MSIL? Posso vedere l'MSIL?

+0

Per ottenere da un'espressione a un delegato è possibile richiamare è necessario chiamare 'Compile()' – BrokenGlass

+0

Ok e cosa c'è dietro quel delegato? –

+0

Un metodo (MethodInfo) – Jeff

risposta

44

Quello che mi interessa è il metodo Compile(). In qualche modo produce vero MSIL?

Sì. Il metodo Compile esegue un visitatore sul blocco body lambda e genera IL in modo dinamico per ogni sottoespressione.

Se sei interessato a imparare come sputare IL te stesso, vedi this "Hello World" example of how to use Lightweight Codegen. (Prendo atto che se sei nella sfortunata posizione di dover usare Lightweight Codegen in un appdomain parzialmente attendibile, le cose possono diventare un po 'strane in un mondo con la visibilità di restrizione ristretta, vedi Shawn Farkas's article sull'argomento se ti interessa.)

Posso vedere l'MSIL?

Sì, ma è necessario uno speciale "visualizzatore". Il visualizzatore che ho usato per eseguire il debug Compile() mentre stavo realizzazione del mio porzioni di esso può essere scaricato qui:

http://blogs.msdn.com/b/haibo_luo/archive/2005/10/25/484861.aspx

+2

Molto impressionante, anche se mi fa male alla testa. –

7

Un'espressione rappresenta una struttura di dati sotto forma di un albero di espressioni - utilizzando Compile() questo albero di espressioni può essere compilato in codice eseguibile sotto forma di delegato (che è una chiamata "metodo").

Dopo la compilazione, è quindi possibile richiamare normalmente il delegato: nell'esempio il delegato è un numero Func<string,int,int,string>. Questo approccio potrebbe essere necessario quando si crea dinamicamente la struttura dell'espressione in base a dati disponibili solo in fase di esecuzione con l'obiettivo finale di creare ed eseguire il delegato corrispondente.

Non è possibile visualizzare il "codice" per il delegato. L'albero di espressione stesso su cui è basato è il più vicino.

+0

Grazie! Quello che ancora non capisco è come può essere eseguito il delegato. Suppongo che ci debba essere un bytecode, da qualche parte ... –

+0

Forse fuori tema, ma mi chiedo quali siano le penalizzazioni delle prestazioni per generare tutto questo IL in modo dinamico. –

0

La risposta a questo è ora in parte superata, in quanto è ora solo a volte ciò che accade.

La compilazione di espressioni in IL richiede Reflection.Emit che non è disponibile tutto il tempo, in particolare con AOT. Quindi in questi casi invece di compilare in IL l'espressione è "compilata" in una lista di oggetti che rappresentano istruzioni. Ognuna di queste istruzioni ha un metodo Run che lo induce a svolgere l'azione appropriata, lavorando su una pila di valori così come l'IL funziona su una pila. Un metodo che chiama Run su questi oggetti può quindi essere restituito come delegato.

Generalmente l'esecuzione di tale delegato è più lenta di jing IL, ma è l'unica opzione quando la compilazione in IL non è disponibile e il passo di compilazione è spesso più veloce, quindi molto spesso il tempo totale di compilazione + esecuzione è minore con l'interprete che con IL per le espressioni one-off.

Per tale ragione, in.NET Core ora ha un sovraccarico di Compile che richiede un'interpretazione booleana di richiesta anche se è disponibile la compilazione in IL.

Tutto ciò rappresenta un interessante mix di lingue; Le espressioni stesse sono un linguaggio, l'assembly è scritto in C#, può essere compilato in IL e gli oggetti di istruzione interpretati costituiscono una quarta lingua.