2008-11-26 12 views
1

Je génère des méthodes getter compilées lors de l'exécution pour un membre donné. Pour l'instant, mon code suppose simplement que le résultat de la méthode getter est une chaîne (ça marche bien pour tester). Cependant, je voudrais faire ce travail avec une classe de convertisseur personnalisé que j'ai écrit, voir ci-dessous, référence "ConverterBase" que j'ai ajouté.Comment générer un lambda compilé avec des appels de méthodes?

Je ne peux pas comprendre comment ajouter l'appel à la classe de convertisseur à mon arbre d'expression. Je cherche ce qu'il faut mettre dans la deuxième zone TODO (je peux gérer le premier :)). Le lambda compilé résultant devrait prendre une instance de type U en tant que param, appeler la fonction d'accès membre spécifiée, puis appeler la méthode "FieldToString" du convertisseur avec le résultat, et retourner la chaîne résultante.

Répondre

5

Pouvez-vous illustrer ce que (si c'était du C# régulier) vous voulez que l'expression évalue? Je peux écrire l'expression assez facilement - je ne comprends pas bien la question ...

(modifier re commentaire) - dans ce cas, ce sera quelque chose comme:

ConverterBase typeConverter = new ConverterBase(); 
    var target = Expression.Parameter(typeof(U), "target"); 
    var getter = Expression.MakeMemberAccess(target, info); 
    var converter = Expression.Constant(typeConverter, typeof(ConverterBase)); 

    return Expression.Lambda<Func<U, string>>(
    Expression.Call(converter, typeof(ConverterBase).GetMethod("FieldToString"), 
     getter), target).Compile(); 

Ou si le type refuse de lier, vous aurez besoin d'injecter une conversion/conversion:

MethodInfo method = typeof(ConverterBase).GetMethod("FieldToString"); 
    return Expression.Lambda<Func<U, string>>(
     Expression.Call(converter, method, 
      Expression.Convert(getter, method.GetParameters().Single().ParameterType)), 
      target).Compile(); 
+0

Parfait. Fonctionne comme un charme. Je me suis heurté au problème de la distribution, mais je suis revenu ici et j'ai vu cette réponse ... Merci! – TheSoftwareJedi

4

Vous devez placer l'objet dans un ExpressionConstant, par ex. en utilisant Expression.Constant. Voici un exemple:

class MyConverter 
{ 
    public string MyToString(int x) 
    { 
     return x.ToString(); 
    } 
} 

static void Main() 
{ 
    MyConverter c = new MyConverter(); 

    ParameterExpression p = Expression.Parameter(typeof(int), "p"); 
    LambdaExpression intToStr = Expression.Lambda(
     Expression.Call(
      Expression.Constant(c), 
      c.GetType().GetMethod("MyToString"), 
      p), 
     p); 

    Func<int,string> f = (Func<int,string>) intToStr.Compile(); 

    Console.WriteLine(f(42)); 
    Console.ReadLine(); 
} 
+0

Expression.Constant - FTW. Merci. Je vais essayer maintenant et attribuer la victoire si c'est bon. Merci! – TheSoftwareJedi

+0

vous avez manqué mon appel d'accès de membre imbriqué, mais c'était assez facile à ajouter à l'arbre. Merci encore – TheSoftwareJedi

+0

Je ne l'ai pas manqué - Je croyais avoir vu votre dilemme et m'y suis adressé spécifiquement :) Je travaille sur des compilateurs dans mon travail de jour, donc c'était assez clair. –

Questions connexes