从Expression创建树

时间:2014-05-05 17:07:51

标签: c# lambda expression-trees

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

我希望有一个图表(使用Expression创建),其结构类似于

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

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

更新: 可能我不够明确 - 我希望有一个采用Linq的代码(在表达式中,所以没有花括号) 并给我一个复合数据结构,其中包含我上面描述的组件(类MyNode {...})。

所以它应该像这样工作:

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

ExpressionVisitor遍历Expression树并在遇到的每个节点上调用Visit方法 - 没关系。不幸的是,它只需要单个参数 (表达式)所以我不知道它在什么情况下(在哪个父项下)。如果它有像​​Visit(Expression parent,Expression child)这样的签名,那么它会很容易 通过重写Visit方法构建MyNode节点树。

1 个答案:

答案 0 :(得分: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);

这不需要尝试假装此节点图表示代码表达式时不会出现混乱。