表达式树:将 <variable> + 1 / <variable> -1 等表达式分别替换为递增/递减操作
Expression Tree: replace expressions like <variable> + 1 / <variable> -1 with increment / detriment operations respectively
我想用表达式树将 () => a - 1 + b + 1
lambda 转换成类似 () => a-- + b++
的东西。
我实现了继承自 ExpressionVisitor.cs
的 class ExpressionTreeTransformer.cs
并覆盖了 VisitBinary
方法:
protected override Expression VisitBinary(BinaryExpression node)
{
if (!TryGetNumberValueFromExpressionNode(node.Left, out var leftNodeValue))
{
return base.VisitBinary(node);
}
if (!TryGetNumberValueFromExpressionNode(node.Right, out var rightNodeValue) || rightNodeValue != 1)
{
return base.VisitBinary(node);
}
var resultedExpression = node.NodeType switch
{
ExpressionType.Add => Expression.Increment(Expression.Constant(leftNodeValue)),
ExpressionType.Subtract => Expression.Decrement(Expression.Constant(leftNodeValue)),
_ => base.VisitBinary(node)
};
return resultedExpression;
}
如果像 () => (a - 1) + (b + 1)
这样应用括号,它工作正常,但如果我们尝试 () => a - 1 + b + 1
经过一些调查,我发现这是表达式树构建节点的方式的原因。
没有括号的步骤如下:
- 左(a - 1) + 右(b)
- 左(1 步的结果)+ 右(1)
表达式节点在处理程序链中处理:
_expressionHandlers = new MemberExpressionHandler();
_expressionHandlers.SetSuccessor(new ConstantExpressionHandler());
变量处理程序:
public class MemberExpressionHandler : AbstractTreeExpressionHandler
{
public override bool Handle(Expression expressionNode, out int nodeValue)
{
if (expressionNode is MemberExpression memberExpression)
{
var constantExpression = memberExpression.Expression as ConstantExpression;
var field = (FieldInfo)memberExpression.Member;
if (constantExpression != null)
{
var value = field.GetValue(constantExpression.Value);
var isNumber = int.TryParse(value.ToString(), out nodeValue);
if (isNumber)
{
return true;
}
}
}
else
{
if (_successor != null)
{
return _successor.Handle(expressionNode, out nodeValue);
}
}
nodeValue = 0;
return false;
}
}
常量处理程序:
public class ConstantExpressionHandler : AbstractTreeExpressionHandler
{
public override bool Handle(Expression expressionNode, out int nodeValue)
{
var isConstant = expressionNode is ConstantExpression;
var isNumber = int.TryParse(((ConstantExpression)expressionNode).Value.ToString(), out nodeValue);
if (isConstant && isNumber)
{
return true;
}
return false;
}
}
问:我被卡住了,请分享您如何正确解决此任务的经验
P.s 结果:
- 带括号:() =>
(Decrement(0) + Increment(1))
- 没有:
() => ((Decrement(0) +
value(ExpressionTreeModule.Program+<>c__DisplayClass0_0).b) + 1)
我认为当您找到 1
的常数加法或减法时,您需要检查左侧并确定是否可以将 addition/subtraction 提升为 increment/decrement.这是我的示例代码:
public class UnaryConstant1 : ExpressionVisitor {
protected override Expression VisitBinary(BinaryExpression node) {
if (node.Right is ConstantExpression c && c.Type.IsNumeric() && (Int32)c.Value == 1) {
if (node.NodeType == ExpressionType.Add || node.NodeType == ExpressionType.Subtract) {
if (node.Left is MemberExpression) {
if (node.NodeType == ExpressionType.Add)
return Expression.Increment(node.Left);
else
return Expression.Decrement(node.Left);
}
else if (node.Left is BinaryExpression left && (left.NodeType == ExpressionType.Add || left.NodeType == ExpressionType.Subtract)) {
Expression right;
if (node.NodeType == ExpressionType.Add)
right = Expression.Increment(left.Right);
else
right = Expression.Decrement(left.Right);
if (left.NodeType == ExpressionType.Add)
return Expression.Add(Visit(left.Left), right);
else
return Expression.Subtract(Visit(left.Left), right);
}
}
}
return base.VisitBinary(node);
}
}
我想用表达式树将 () => a - 1 + b + 1
lambda 转换成类似 () => a-- + b++
的东西。
我实现了继承自 ExpressionVisitor.cs
的 class ExpressionTreeTransformer.cs
并覆盖了 VisitBinary
方法:
protected override Expression VisitBinary(BinaryExpression node)
{
if (!TryGetNumberValueFromExpressionNode(node.Left, out var leftNodeValue))
{
return base.VisitBinary(node);
}
if (!TryGetNumberValueFromExpressionNode(node.Right, out var rightNodeValue) || rightNodeValue != 1)
{
return base.VisitBinary(node);
}
var resultedExpression = node.NodeType switch
{
ExpressionType.Add => Expression.Increment(Expression.Constant(leftNodeValue)),
ExpressionType.Subtract => Expression.Decrement(Expression.Constant(leftNodeValue)),
_ => base.VisitBinary(node)
};
return resultedExpression;
}
如果像 () => (a - 1) + (b + 1)
这样应用括号,它工作正常,但如果我们尝试 () => a - 1 + b + 1
经过一些调查,我发现这是表达式树构建节点的方式的原因。 没有括号的步骤如下:
- 左(a - 1) + 右(b)
- 左(1 步的结果)+ 右(1)
表达式节点在处理程序链中处理:
_expressionHandlers = new MemberExpressionHandler();
_expressionHandlers.SetSuccessor(new ConstantExpressionHandler());
变量处理程序:
public class MemberExpressionHandler : AbstractTreeExpressionHandler
{
public override bool Handle(Expression expressionNode, out int nodeValue)
{
if (expressionNode is MemberExpression memberExpression)
{
var constantExpression = memberExpression.Expression as ConstantExpression;
var field = (FieldInfo)memberExpression.Member;
if (constantExpression != null)
{
var value = field.GetValue(constantExpression.Value);
var isNumber = int.TryParse(value.ToString(), out nodeValue);
if (isNumber)
{
return true;
}
}
}
else
{
if (_successor != null)
{
return _successor.Handle(expressionNode, out nodeValue);
}
}
nodeValue = 0;
return false;
}
}
常量处理程序:
public class ConstantExpressionHandler : AbstractTreeExpressionHandler
{
public override bool Handle(Expression expressionNode, out int nodeValue)
{
var isConstant = expressionNode is ConstantExpression;
var isNumber = int.TryParse(((ConstantExpression)expressionNode).Value.ToString(), out nodeValue);
if (isConstant && isNumber)
{
return true;
}
return false;
}
}
问:我被卡住了,请分享您如何正确解决此任务的经验
P.s 结果:
- 带括号:() =>
(Decrement(0) + Increment(1))
- 没有:
() => ((Decrement(0) + value(ExpressionTreeModule.Program+<>c__DisplayClass0_0).b) + 1)
我认为当您找到 1
的常数加法或减法时,您需要检查左侧并确定是否可以将 addition/subtraction 提升为 increment/decrement.这是我的示例代码:
public class UnaryConstant1 : ExpressionVisitor {
protected override Expression VisitBinary(BinaryExpression node) {
if (node.Right is ConstantExpression c && c.Type.IsNumeric() && (Int32)c.Value == 1) {
if (node.NodeType == ExpressionType.Add || node.NodeType == ExpressionType.Subtract) {
if (node.Left is MemberExpression) {
if (node.NodeType == ExpressionType.Add)
return Expression.Increment(node.Left);
else
return Expression.Decrement(node.Left);
}
else if (node.Left is BinaryExpression left && (left.NodeType == ExpressionType.Add || left.NodeType == ExpressionType.Subtract)) {
Expression right;
if (node.NodeType == ExpressionType.Add)
right = Expression.Increment(left.Right);
else
right = Expression.Decrement(left.Right);
if (left.NodeType == ExpressionType.Add)
return Expression.Add(Visit(left.Left), right);
else
return Expression.Subtract(Visit(left.Left), right);
}
}
}
return base.VisitBinary(node);
}
}