2010-02-26 11 views
16

J'ai un code qui génère divers délégués Func<> en utilisant System.Linq.Expressions et Expression.Lambda<Func<>>.Compile() etc. Je voudrais pouvoir sérialiser les fonctions générées dans un ensemble pour une utilisation ultérieure. Dans le passé, j'ai fait quelques choses avec System.Reflection.Emit mais maintenant que Linq Expressions je préfère ne pas reprendre cette route.Comment puis-je émettre une expression System.Linq.Expression?

Existe-t-il un mécanisme pour sérialiser une expression compilée ou une sorte de pont de l'espace de noms Expressions vers l'espace de noms Emit?

Modifier

Certains arrière-plan pour le contexte: Je travaille sur un moteur de recherche (la plupart du temps pour mon propre plaisir et l'édification). Étant donné une instruction SQL je voudrais analyser et transformer en une fonction lambda, puis sérialiser sur le disque pour plus tard (et l'exécution répétée).

Dans le code pseudo Je suis à ce point:

Func<IEnumerable<T>, IEnumerable<T1>> query = Query.Parse<T, T1>("Select field AS A, field1 AS B from T where T.field2 > 5"); 

(où champ, field1 et field2 sont la propriété de type T et A et B sont des propriétés de Type T1 et je peux transmettre n'importe quelle énumération de <T> à query et revenez et une énumération de <T1> qui correspond aux critères de la requête.

Je voudrais donc sérialiser query sur le disque en tant qu'ensemble déjà compilé, donc à une date ultérieure, je peux le charger et évaluer différents ensembles de <T> sans les analyser et les compiler. J'imaginais quelque chose le long des lignes de:

AssemblyBuilder builder = new AssemblyBuilder(...); 
ModuleBuilder module = builder.DefineDynamicModule(...); 
TypeBuilder type = module.DefineType(...); 
type.AddMethod(query); // <--- where this piece does not exist as far as I know 
builder.Emit(...) 

Répondre

3

Je ne sais pas exactement ce que votre plus grande image mais en regardant uniquement à votre deuxième paragraphe, vous pouvez écrire pur code basé sur Expression, construire, puis ouvrez votre assembly dans Reflector en utilisant le complément de langage "Reflection.Emit". Ce morceau de meta-meta trickery vous montrera les instructions Reflection.Emit nécessaires pour générer votre code Expression/Lambda dynamiquement.

-Oisin

+0

Je pense que je vois ce que vous obtenez, mais si vous regardez mon édition: Je ne sais pas à quoi ressembleront les expressions avant l'évaluation de l'exécution de l'entrée. – dkackman

3

Je ne pense pas qu'il n'y a aucun moyen de le faire. Après tout, un Expression peut capturer des valeurs d'exécution arbitraires, qui ne peuvent pas être sérialisées dans un assembly.

Il semblerait que vous pourriez contourner cela en appelant expr.Compile().Method.GetMethodBody().GetILAsByteArray() pour obtenir l'IL comme octets, qui pourraient ensuite être écrits dans un MethodBuilder dans un ensemble que vous pourriez ensuite écrire dans un fichier. Malheureusement, cela ne fonctionnera pas - l'appel GetMethodBody() échoue car le délégué est dynamique.

3

LambdaExpression a une méthode CompileToMethod qui cible un MethodBuilder. En utilisant ceci et Reflection.Emit, vous devriez être capable de créer une classe et de l'écrire dans un assembly.