LINQ 表达式树是正确的树吗?

Posted

技术标签:

【中文标题】LINQ 表达式树是正确的树吗?【英文标题】:Are LINQ expression trees proper trees? 【发布时间】:2012-02-17 17:06:33 【问题描述】:

LINQ 表达式树是否是正确的树,例如没有循环的图(有向与无向,***似乎不太一致)?以下 C# 表达式的表达式树的根是什么?

(string s) => s.Length

表达式树看起来像这样,“->”表示节点的属性名称,另一个节点可以通过它访问。

     ->Parameters[0]
 Lambda---------Parameter(string s)
    \               /
     \->Body       /->Expression
      \           /
      Member(Length)

当使用 ExpressionVisitor 访问 LambdaExpression 时,ParameterExpression 被访问了两次。有没有办法使用 ExpressionVisitor 访问 LambdaExpression,以便所有节点都被访问一次,并且以特定的、众所周知的顺序(前序、中序、后序等)?

【问题讨论】:

你为什么需要这个,你为什么在乎? @DanielHilgarth 我认为这是一个关于表达式树的基本概念如何工作的合理问题。这是一个问答网站,提问者似乎对表达式树的工作原理感到好奇。 这个问题可能是为了投票,但很有趣。 有谁知道数学表达式树属于什么分支?我想看看数学概念 @DavidHoerster:这确实是一个合理的问题,但通常情况下,人们提出这样的问题是为了解决一些问题。我宁愿知道最初的问题并帮助解决它。 【参考方案1】:

有点,是的。 LambdaExpression 的实际“主干”(如果你愿意的话)是 .Body;参数是关于树结构(以及它需要什么)的必要元数据,但顶部的.Parameters(您的虚线)并不是树功能图的真正一部分 - 只有当这些节点稍后使用时在树的实际主体中,它们很有趣,作为值替换。

ParameterExpression 被访问两次是必不可少的,因此有人可以根据需要交换参数 - 例如,使用相同数量的参数构建一个全新的 LambdaExpression,但参数实例不同(可能会改变类型)。

顺序将相当稳定,但应视为实现细节。例如,给定一个像Add(A,B) 这样的节点,无论我访问A-first 还是B-first 应该没有语义差异。

【讨论】:

谢谢。很高兴知道 Expression 类的哪些属性构成了表达式树中的“正确”边缘。 @cynic 几乎所有 Expression 不是 LambdaExpression.Parameters 的东西!虽然我只是真正考虑 3.5 风格的表达方式,但我想不出任何其他人。在某些 4.0 节点类型上可能还有一些其他类似的元数据值...【参考方案2】:

只是为 Marc 的正确答案添加一点:

LINQ 表达式树是无环的有向图吗?

首先,是的,表达式树是一个有向无环图——一个有向无环图。

我们知道它们是非循环的,因为表达式树是不可变的,因此必须从叶子向上构建。在这种情况下,没有办法进行循环,因为循环中的所有节点都必须最后分配,显然这不会发生。 p>

因为这些部分是不可变的,所以“树”这个表达式实际上不必是树本身。正如 Marc 指出的那样,您需要重新使用参数的引用;这就是我们如何确定何时使用声明的参数。重复使用其他部分虽然合法,但有点奇怪。例如,如果您想为(int x)=>(x + 1) * (x + 1) 的主体表示表达式树,您可以为(x + 1) 创建一个表达式树,然后创建一个乘法节点,其中两个子节点都是该表达式树。

当使用 ExpressionVisitor 访问 LambdaExpression 时,ParameterExpression 被访问了两次。有没有办法使用 ExpressionVisitor 访问 LambdaExpression,以便所有节点都被访问一次,并且以特定的、众所周知的顺序(前序、中序、后序等)?

ExpressionVisitor 是一个抽象类。您可以制作自己的具有您喜欢的语义的具体版本。例如,您可以重写 Visit 方法,使其维护一个已看到的节点的 HashSet,并且不对之前接受的节点调用 Accept。

【讨论】:

感谢@ericlippert,这让它更清楚了。还有一个问题:是否可以在第二个(非嵌套)lambda 中重用相同的参数实例,甚至在第二个 lambdas 参数集合中使用它? lambda1 : (x) => x.Y lambda2 : (x) => x.Z used in source.Where(lambda1).OrderBy(lambda2) 这是 C# LINQ 不会产生的东西。但它是否被视为有效的表达式树? @Tom67:这是一个问答网站。发布这个问题! 谢谢@ericlippert,现在希望能得到最终答案here。

以上是关于LINQ 表达式树是正确的树吗?的主要内容,如果未能解决你的问题,请参考以下文章

所有黑色节点的树是红黑树吗?

C#中的表达式树简介

判断一把刀剑的好坏是用性能测试来决定的吗?

数据结构原来这个叫树

表达式树

Expression