2009-03-30 9 views
13

The dynamic language runtime (DLR) имеет некоторые довольно прохладно код для выражения, в том числе некоторые очень хороший код, чтобы распечатать деревья выражений, которые я хочу использовать так, что:Распечатайте Linq Expression Tree Иерархии

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

Выходы:

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

Я нашел некоторый код в сети, чтобы сделать это, но обнаружил, что он работает только в том случае, если выражение не принимает аргументов.

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

Затем я обнаружил реализацию DLR подобного метода. Однако DLR имеет свои собственные пользовательские реализации класса Expression и многие другие стандартные типы C#, поэтому я немного запутался. Кто-нибудь знает, как я могу реализовать вышеизложенное?

ответ

13

Как насчет:

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

Очень хорошо, спасибо. – 2009-03-31 12:34:50

+1

В приведенных выше методах кода. Evaluate и .Indent не распознаются моим VS2012. Что мне нужно установить или добавить ссылку? – user3057544

+0

Это старый вопрос, но для ответа user3057544, вероятно, лучше поставить его в статический класс и ссылаться на него как метод расширения на LambdaExpression ... или хотя бы использовать его в статическом классе, как это делает Марк. – dhysong