简体   繁体   中英

Creating tree from Expression

How can I create tree (graph) from System.Linq.Expressions.Expression?

I wish to have a graph (created from Expression) with nodes of a structure like

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. ).

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 { ...} ).

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. Unfortunately, it takes only single parameter (Expression) so I don't know in what context (under which parent) it is working. 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.

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. If you have an object that has an IEnumerable representing it's children, like so:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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