2014-05-05 160 views
0

如何从System.Linq.Expressions.Expression创建树(图)?从表达式创建树

我希望有一个结构的节点的图(从表达式创建)像

MyNode 
{ 
    Expression _internalExpression = ... 
    MyNode Parent {get ...} 
    IEnumerable<MyNode> Children {get ...} 
} 

我想过从ExpressionVisitor推导,但我不知道如何从推断父子关系 被调用的方法(Visit,VisitBinary等)。

更新: 也许我是不够明确的 - 我希望有需要的Linq代码(在表现形式,所以没有大括号) 并给我回一个复合数据结构,我有分量如上所述(class MyNode {...})。

因此,它应该像这样工作:

MyNode root = TreeCreator.FromExpression((x,y) => x + y);

的ExpressionVisitor遍历表达式树,并调用访问方法遇到的每一个节点上 - 这是确定。不幸的是,它只需要单个参数 (表达式),所以我不知道它在哪个上下文(在哪个父项下)工作。如果它具有像Visit(Expression parent,Expression child)这样的签名,那么通过重写Visit方法可以很容易地构建MyNode节点的树。

+2

如果你的对象实际上并不代表代码表达式,那么我会阻止你这样做。这对你的类型的用户来说会非常困惑,并且不会帮你解决那么多问题。迭代一个类似于你刚刚提供的对象比迭代一个Expression表达式更容易。 – Servy

回答

2

这是容易遍历在可比你在你的问题已经描述比它试图穿越一个Expression树的方式定义的图表。如果你有一个具有代表其子项的IEnumerable,像这样的对象:

class MyNode 
{ 
    MyNode Parent { get; private set; } 
    IEnumerable<MyNode> Children { get; private set; } 
} 

然后穿越它,你只需要几行代码:

public static IEnumerable<T> Traverse<T>(
    this IEnumerable<T> source 
    , Func<T, IEnumerable<T>> childrenSelector) 
{ 
    var stack = new Stack<T>(source); 
    while (stack.Any()) 
    { 
     var next = stack.Pop(); 
     yield return next; 
     foreach (var child in childrenSelector(next)) 
      stack.Push(child); 
    } 
} 

现在我们可以这样写:

IEnumerable<MyNode> nodes = GetNodesFromSomewhere(); 
var allNodesInTree = nodes.Traverse(node => node.Children); 

而这不需要试图假装这个节点图表表示代码表达式时的混乱。