首页 文章

从Expression创建树

提问于
浏览
0

如何从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方法 - 没关系 . 不幸的是,它只需要单个参数(Expression),所以我不知道它在哪个上下文(在哪个父项下) . 如果它有一个像Visit(Expression parent,Expression child)这样的签名,那么通过重写Visit方法可以很容易地构建MyNode节点树 .

1 回答

  • 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);
    

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

相关问题