2009-03-30 29 views
13

Các dynamic language runtime (DLR) có một số mã đẹp, thoáng mát cho biểu thức, trong đó có một số mã rất đẹp để in ra cây biểu thức mà tôi muốn sử dụng để:In ra LINQ Biểu Tree Hierarchy

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

Đầu ra:

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

Tôi tìm thấy một số mã trên mạng để thực hiện điều này nhưng thấy rằng nó chỉ hoạt động nếu các biểu thức không có đối số.

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

Sau đó, tôi đã phát hiện việc triển khai DLR của một phương pháp tương tự. Tuy nhiên, DLR có các triển khai tùy chỉnh riêng của lớp Expression và nhiều loại C# tiêu chuẩn khác nên tôi có chút bối rối. Bất cứ ai biết làm thế nào tôi có thể thực hiện ở trên?

Trả lời

13

Làm thế nào về:

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

Rất tốt, cảm ơn. –

+1

Trong các phương pháp mã ở trên .Đánh giá và .Indent không được nhận dạng bởi VS2012 của tôi. Tôi cần những gì để cài đặt hoặc thêm tham chiếu? – user3057544

+0

Đây là một câu hỏi cũ, nhưng để trả lời user3057544, có lẽ tốt hơn nên đặt nó trong một lớp tĩnh và tham khảo nó như một phương thức mở rộng của LambdaExpression ... hoặc ít nhất sử dụng nó trong một lớp tĩnh như Marc làm ở trên. – dhysong