表达式树:分别用增量/有害操作替换诸如<variable> + 1 / <variable> -1之类的表达式

时间:2019-10-24 07:45:57

标签: c# linq expression expression-trees

我想使用表达式树将() => a - 1 + b + 1 lambda转换为类似() => a-- + b++的东西。

我实现了从ExpressionTreeTransformer.cs继承并覆盖ExpressionVisitor.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

经过一番调查,我发现原因是表达式树如何构建节点。 没有括号的步骤如下:

  1. 左(a-1)+右(b)
  2. 左(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 个答案:

答案 0 :(得分:1)

我认为当您发现1的恒定加减时,您需要检查左侧,并确定是否可以将加减乘以增量/减量。这是我的示例代码:

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);
    }
}