将表达式中的参数替换为常量

Tim*_*ann 2 .net c# reflection expression

我有一个类型的表达式Expression<Func<TElement, TElement, bool>>和一个类型的常量TElement。我需要一个类型的表达式Expression<Func<TElement, bool>>,其中一个参数被常量替换。换句话说,我需要以下方法的主体:

public static Expression<Func<TElement, bool>> ReplaceParameter<TElement>
(
    Expression<Func<TElement, TElement, bool>> inputExpression,
    TElement element
)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果我打电话ReplaceParameter((i1, i2) => i1 > i2, 5),我预计结果是i => i > 5

我在想,它也许能够递归地解构然后重建输入表达式,并用常量表达式替换所有出现的第二个参数。由于有很多不同的表达方式,我不确定如何做到这一点。

Mar*_*ell 6

ExpressionVisitor是你的朋友:

static void Main()
{
    Expression<Func<int, int, bool>> before = (x, y) => x * 2 == y + 1;
    var after = ReplaceParameter(before, 3);
    Console.WriteLine(after);
}
public static Expression<Func<TElement, bool>> ReplaceParameter<TElement>
(
    Expression<Func<TElement, TElement, bool>> inputExpression,
    TElement element
)
{
    var replacer = new Replacer(inputExpression.Parameters[0],
        Expression.Constant(element, typeof(TElement)));
    var body = replacer.Visit(inputExpression.Body);
    return Expression.Lambda<Func<TElement, bool>>(body,
        inputExpression.Parameters[1]);
}
class Replacer : ExpressionVisitor
{
    private readonly Expression _from, _to;
    public Replacer(Expression from, Expression to)
    {
        _from = from;
        _to = to;
    }
    public override Expression Visit(Expression node)
        => node == _from ? _to : base.Visit(node);
}
Run Code Online (Sandbox Code Playgroud)

请注意,这不会自动折叠纯常量表达式,即显示的代码会导致:

y => ((3 * 2) == (y + 1))
Run Code Online (Sandbox Code Playgroud)

但是,如果您愿意,您可以尝试查找BinaryExpression仅作为ConstantExpression输入的节点,并再次在 内部直接评估节点Replacer