简体   繁体   English

从Expression创建树

[英]Creating tree from Expression

How can I create tree (graph) from System.Linq.Expressions.Expression? 如何从System.Linq.Expressions.Expression创建树(图)?

I wish to have a graph (created from Expression) with nodes of a structure like 我希望有一个图形(从Expression创建)与结构的节点

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

I thought about deriving from ExpressionVisitor but I don't know how to infer the parent-child relation from within method being called (Visit, VisitBinary etc. ). 我想过从ExpressionVisitor派生,但我不知道如何从被调用的方法(Visit,VisitBinary等)中推断出父子关系。

Update: Probably I wasn't explicit enough - I wish to have a code that takes a Linq (in the expression form, so no curly brackets) and gives me back a composite data structure with components that I have described above ( class MyNode { ...} ). 更新:可能我不够明确 - 我希望有一个代码采用Linq(在表达式中,所以没有花括号)并给我一个复合数据结构,其中包含我上面描述的组件(类MyNode { ......})。

So it should work like this: 所以它应该像这样工作:

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

The ExpressionVisitor traverses the Expression tree and invokes Visit method on every node encountered - that's ok. ExpressionVisitor遍历Expression树并在遇到的每个节点上调用Visit方法 - 没关系。 Unfortunately, it takes only single parameter (Expression) so I don't know in what context (under which parent) it is working. 不幸的是,它只需要单个参数(Expression),所以我不知道它在哪个上下文(在哪个父项下)。 If it had a signature like Visit(Expression parent, Expression child), then it would be easy to build the tree of MyNode nodes by overriding the Visit method. 如果它有一个像Visit(Expression parent,Expression child)这样的签名,那么通过重写Visit方法可以很容易地构建MyNode节点树。

It is far easier to traverse a graph that is defined in a manner comparable to what you have described in your question than it is to try to traverse an Expression tree. 要容易得多遍历了在可比你在你的问题已经描述比它试图穿越的方式定义的图形Expression树。 If you have an object that has an IEnumerable representing it's children, like so: 如果你有一个IEnumerable对象代表它的子对象,就像这样:

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

Then to traverse it you only need a few lines of code: 然后遍历它你只需要几行代码:

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

We can now write: 我们现在可以写:

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

And this requires none of the messiness of trying to pretend that this node graph represents code expressions when it doesn't. 并且这不需要尝试假装此节点图表示代码表达式时不会出现混乱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM