2009-03-30 6 views
13

Le dynamic language runtime (DLR) a un code assez cool pour l'expression de, y compris un code très agréable d'imprimer des arbres d'expression que je veux utiliser afin que:Imprimez Linq Expression Arbre Hiérarchie

int a = 1; 
int b = 2; 
Expression<Func<int, int>> expression = (c) => a + (b * c) 
expression.Evaluate(5, stringBuilder) 

Sorties:

(5) => a + (b * c) = 11 Where 
    a = 1 
    b * c = 10 Where 
      b = 2 
      c = 5 

J'ai trouvé du code sur le net pour le faire mais j'ai trouvé que cela ne fonctionne que si l'expression ne contient aucun argument.

http://incrediblejourneysintotheknown.blogspot.com/2009/02/displaying-nested-evaluation-tree-from.html

J'ai découvert alors la mise en œuvre de DLR d'une méthode similaire. Cependant, le DLR a ses propres implémentations personnalisées de la classe Expression et de nombreux autres types de C# standard, donc j'ai été un peu confus. Quelqu'un sait comment je peux mettre en œuvre ce qui précède?

Répondre

13

Que diriez-vous:

using System; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Text; 
using System.Text.RegularExpressions; 

static class Program 
{ 
    static void Main() 
    { 
     int a = 1, b = 2; 
     StringBuilder sb = new StringBuilder(); 
     Expression<Func<int, int>> expression = (c) => a + (b * c); 
     expression.Evaluate(sb, 5); 
     // now fix the capture class names (from a and b) 
     string s = sb.ToString(); 
     s = Regex.Replace(s, @"value\([^)]+\)\.", ""); 
     Console.WriteLine(s); 
    } 
    public static void Evaluate(this LambdaExpression expr, StringBuilder builder, params object[] args) 
    { 
     var parameters = expr.Parameters.ToArray(); 
     if (args == null || parameters.Length != args.Length) throw new ArgumentException("args"); 
     Evaluate(expr.Body, 0, builder, parameters, args); 
    } 
    private static StringBuilder Indent(this StringBuilder builder, int depth) 
    { 
     for (int i = 0; i < depth; i++) builder.Append(" "); 
     return builder; 
    } 
    private static void Evaluate(this Expression expr, int depth, StringBuilder builder, ParameterExpression[] parameters, object[] args) 
    { 
     builder.Indent(depth).Append(expr).Append(" = ").Append(Expression.Lambda(expr, parameters).Compile().DynamicInvoke(args)); 

     UnaryExpression ue; 
     BinaryExpression be; 
     ConditionalExpression ce; 

     if ((ue = expr as UnaryExpression) != null) 
     { 
      builder.AppendLine(" where"); 
      Evaluate(ue.Operand, depth + 1, builder, parameters, args); 
     } 
     if ((be = expr as BinaryExpression) != null) 
     { 
      builder.AppendLine(" where"); 
      Evaluate(be.Left, depth + 1, builder, parameters, args); 
      Evaluate(be.Right, depth + 1, builder, parameters, args);     
     } 
     else if ((ce = expr as ConditionalExpression) != null) 
     { 
      builder.AppendLine(" where"); 
      Evaluate(ce.Test, depth + 1, builder, parameters, args); 
      Evaluate(ce.IfTrue, depth + 1, builder, parameters, args); 
      Evaluate(ce.IfFalse, depth + 1, builder, parameters, args); 
     } 
     else 
     { 
      builder.AppendLine(); 
     } 
    } 

} 
+0

Très bien, merci. –

+1

Dans les méthodes de code ci-dessus. Évaluer et .Indent ne sont pas reconnus par mon VS2012. De quoi ai-je besoin pour installer ou ajouter une référence? – user3057544

+0

Ceci est une vieille question, mais pour répondre à l'utilisateur 3057544, il est probablement préférable de le mettre dans une classe statique et de le référencer comme une méthode d'extension d'une LambdaExpression ... ou au moins de l'utiliser dans une classe statique. – dhysong

Questions connexes