Я хотел бы преобразовать () => a - 1 + b + 1
лямбда во что-то вроде () => 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
После некоторого исследования я выяснил, что причина в том, какузлы построения дерева выражений. Без скобок шаги выглядят следующим образом:
- влево (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;
}
}
Q: Я застрялПожалуйста, поделитесь своим опытом, как правильно решить эту задачу
Ps результаты:
- С круглыми скобками: () =>
(Decrement(0) + Increment(1))
- Без:
() => ((Decrement(0) +
value(ExpressionTreeModule.Program+<>c__DisplayClass0_0).b) + 1)