【问题标题】:Rewritten expression calls operator method ... but the original node had no operator method重写表达式调用运算符方法...但原始节点没有运算符方法
【发布时间】:2016-04-05 12:23:25
【问题描述】:

我正在尝试更改表达式树的一部分,其中将 MyEnum 类型的属性 X 与某个值 x 进行比较:

$model.X == .Constant<MyEnum>(x)

我想修改树以替换比较,将Guid 类型的属性 Y 与值 y(将从 x 派生)进行比较。

$model.Y == .Constant<Guid>(y)

所以我从ExpressionVisitor 继承,并覆盖VisitMember 以用Y 代替X,我已经覆盖VisitConstant 以用y 代替x。

运行它会产生以下InvalidOperationException:

System.InvalidOperationException : 重写的表达式调用运算符方法'Boolean op_Equality(System.Guid, System.Guid)',但原始节点没有运算符方法。如果这是故意的,请覆盖“VisitBinary”并将其更改为允许此重写。

我的主要问题是:我必须在VisitBinary 中做什么?我的问题是:为什么异常消息告诉原始节点没有操作符方法。我认为这不是真的。它肯定没有op_Equality(System.Guid, System.Guid),但我认为它有MyEnum 类型的相等运算符。

【问题讨论】:

    标签: c# expression-trees linq-expressions


    【解决方案1】:

    我猜MyEnum 是某种Enum 类型。

    Enum 类型不需要运算符方法,因为 CIL 直接为它们处理相等比较(内置的整数、浮点和布尔类型也是如此)。

    无法通过BinaryExression.Update() 更改方法(这将在您的访问者中显式调用或隐式调用,因为您的访问者更改了左右表达式中的一个或两个,这是这种情况下的默认行为)您必须让VisitBinary() 创建并通过对Expression.Equal() 的适当调用返回一个新的BinaryExpression。

    【讨论】:

    • 在任何情况下重写 VisitBinary 都是更好的选择,因为它将所有逻辑放在一个位置。我想知道在执行此操作之前 OPs 代码必须是什么样子,可能与通过 VisitC 调用携带的实例状态令人费解。在 VisitBinary 中,他可以只检查两个孩子,如果匹配则执行重写。 +1
    • 这是一个非常有趣的见解。我不知道 Expression 类在编译之前就已经包含了 CIL“知识”。
    • 它更像是工厂方法而不是实例本身。值得注意的是,如果您从具有不同运算符方法的二进制表达式开始,那么更新仍然会失败但出现不同的异常,因此实现细节会影响异常的性质(这可能仍然不理想)但是不是它是否发生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-29
    • 2010-12-31
    • 1970-01-01
    • 2016-09-07
    相关资源
    最近更新 更多