2009-03-30 18 views
13

El dynamic language runtime (DLR) tiene un código muy bien para la expresión de, incluyendo un código muy agradable para imprimir árboles de expresión que yo quiero usar de modo que:Imprime expresión LINQ vista de jerarquía

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

Salidas:

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

Encontré un código en la red para hacer esto, pero encontré que solo funciona si la expresión no incluye argumentos.

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

entonces descubrí la implementación DLR de un método similar. Sin embargo, el DLR tiene sus propias implementaciones personalizadas de la clase Expression y muchos otros tipos estándar de C#, así que me confundí un poco. ¿Alguien sabe cómo puedo implementar lo anterior?

Respuesta

13

¿Qué tal:

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

Muy bien, gracias. –

+1

En los métodos de código anteriores .Evaluate y .Indent no son reconocidos por mi VS2012. ¿Qué necesito para instalar o agregar referencia? – user3057544

+0

Esta es una vieja pregunta, pero para responder al usuario3057544, probablemente sea mejor poner esto en una clase estática y hacer referencia a ella como un método de extensión fuera de LambdaExpression ... o al menos usarlo en una clase estática como lo hace Marc anteriormente. – dhysong

Cuestiones relacionadas