【问题标题】:Creating tree from Expression从表达式创建树
【发布时间】:2023-03-15 20:39:02
【问题描述】:

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

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

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

我想过从 ExpressionVisitor 派生,但我不知道如何推断父子关系 从被调用的方法内部(访问、访问二进制等)。

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

所以它应该像这样工作:

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

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

【问题讨论】:

  • 如果您的对象实际上并不代表代码表达式,那么我会劝阻您不要这样做。这会让您的类型的用户非常困惑,并且不会对您有太大帮助。迭代与您刚刚提供的对象类似的对象比迭代 Expression 树要容易很多

标签: c# lambda expression-trees


【解决方案1】:

遍历以与您在问题中描述的方式相当的方式定义的图比尝试遍历 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);

这不需要试图假装这个节点图代表代码表达式而实际上它不代表代码表达式的混乱。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 2018-03-11
    相关资源
    最近更新 更多