如何在 ExpressionVisitor 中计算表达式?
我需要在执行表达式之前使用 ExpressionVisitor 来分析它。根据我的需要,我需要评估除法表达式的正确部分,但我不知道该怎么做。这是我拥有的示例代码:
internal class RulesChecker : ExpressionVisitor
{
private readonly object data;
public RulesChecker(object data)
{
this.data = data;
}
protected override Expression VisitBinary(BinaryExpression node)
{
if (node.NodeType == ExpressionType.Divide)
{
var rightExpression = node.Right;
// compile the right expression and get his value
}
return base.VisitBinary(node);
}
}
假设我要评估以下代码:
Expression<Func<DataInfo, decimal?>> expression = x => x.A / (x.B + x.C);
var rulesChecker = new RulesChecker(data);
rulesChecker.Visit(expression);
在 VisitBinary 函数中,我将收到一个包含除法运算的左右部分的节点。我的问题是,我如何评估在操作的正确部分中将获得的价值?
I need to use ExpressionVisitor to analyse an Expression before executing it. For my needs, i need to evaluate the right part of a Divide expression but i don't know how to do it. Here's a sample code that i have:
internal class RulesChecker : ExpressionVisitor
{
private readonly object data;
public RulesChecker(object data)
{
this.data = data;
}
protected override Expression VisitBinary(BinaryExpression node)
{
if (node.NodeType == ExpressionType.Divide)
{
var rightExpression = node.Right;
// compile the right expression and get his value
}
return base.VisitBinary(node);
}
}
Suppose that i have this code to evaluate:
Expression<Func<DataInfo, decimal?>> expression = x => x.A / (x.B + x.C);
var rulesChecker = new RulesChecker(data);
rulesChecker.Visit(expression);
In the VisitBinary function, i will receive a node that will contain the left and right part of the divide operation. My question is, how can i evaluate the value that i will get in the right part of the operation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我认为这个问题最难的部分是处理变量。所以我首先将变量替换为常量。之后您只需执行并更新表达式即可。
I think the hardest part of this problem is dealing with the variables. So I would start by replacing the variables for constants. After that you just need to execute and update the Expression.
通常您可以使用此方法来计算 lambda 表达式(并传递):
但是,在您的情况下,这不起作用,因为您尝试计算的表达式取决于
x
,而它不能评估,除非您按照 Wiktor 的建议为其指定具体值。为了指定参数的值,您需要如下修改该方法:
但是,此版本的方法必须将表示表达式中的
x
的 ExpressionParameter 对象作为参数以便它知道如何处理传递给 DynamicInvoke() 的值。为了获取适当的
ExpressionParameter
对象,您需要访问根表达式,而不是其节点之一,因此我想在访问者中执行此操作会很尴尬。Usually you could use this method to evaluate a lambda expression (and pass ):
However, in your case this won't work, because the expression you're trying to evaluate depends on
x
, which cannot be evaluated, unless you specify a concrete value for it, as Wiktor suggested.In order to specify a value for the parameter, you need to modify the method as such:
This version of the method, however, must take as a parameter the ExpressionParameter object that represents the
x
in your expression in order for it to know what to do with the value passed toDynamicInvoke()
.In order to obtain the appropriate
ExpressionParameter
object you need access to the root expression, not to one of its nodes, so I guess it would be awkward to do it in a visitor.如果我理解正确的话,您希望将访问表达式的结果返回为修改后的表达式树,该树以某种方式评估了部门的右侧。您可以使用
BinaryExpression
的Update
方法将右侧节点替换为您的值:在此代码中,
newRightExpression
需要属于一种类型继承自Expression
。如果正确的节点计算结果为 double 值,那么您需要将其包装在 ConstantExpression 中:If I understand you correctly, you want to return the result of visiting your expression to be a modified expression tree that has the right-hand sides of divisions evaluated in some way. You would use the
Update
method of theBinaryExpression
to replace the right node with your value:In this code,
newRightExpression
needs to be of a type that inherits fromExpression
. If the right node evaluates to, say, adouble
value, then you would need to wrap it in aConstantExpression
:我认为@w0lf走在正确的道路上。
要从访问者内部获取参数,您需要覆盖 VisitLambda。最好的方法是重写访问者的每个可用方法,并将参数传递给所有方法。
另一种方法是保存最新的参数。实际上,参数数组在整个 lambda 表达式中都是相同的。
这是一段代码,将除法运算的右侧乘以 2 并将其替换到原始表达式中,假设右侧和左侧都是 double 类型。
I think @w0lf is on the correct path.
To get the parameters from within the visitor, you need to override VisitLambda. Best way to do it is to override every available method of the visitor, and pass the parameters to all of your methods.
Another method is to save the latest parameters. Actually, parameters array will be the same throughout a whole lambda expression.
Here is a piece of code, multiplying the right side of a division operation by two and replacing it in the original expression, assuming right side and left side are of type double.