减少LambdaExpression签名

本文关键字:签名 LambdaExpression 减少 | 更新日期: 2023-09-27 18:27:37

我想不出更好的方法来表达这个问题,但我想做的是在计算LambdaExpression之前,通过处理FilterObject的实例,将LambdaExpression的签名从Expression<Func<MyObject, FilterObject, bool>>减少到Expression<Func<MyObject, bool>>

这里有一个快速的例子:

AddFilter("Filter Name", FilterTypes.All,
    (x, y) => GetConjunctionResult(
        x.PersonA.IsSomething, x.PersonB.IsSomething, y.ConjunctionType));
private static bool GetConjunctionResult(bool personA, bool personB,
    ConjunctionType conjunctionType)
{
    switch (conjunctionType)
    {
        case ConjunctionType.Both:
            return personA && personB:
        case ConjunctionType.Either:
            return personA && personB;
        case ConjunctionType.PersonA:
            return personA;
        case ConjunctionType.PersonB:
            return personB;
        case ConjunctionType.Neither:
            return !personA && !personB;
    }
}

因此,我希望AddFilter的重载创建一个FilterObject类型的对象,并将其嵌入到LambdaExpression中,如下所示:

var filter = new FilterObject();
// create Expression<Func<MyObject, bool>> lambda = x => GetConjunctionResult(
//     x.PersonA.IsSomething, x.PersonB.IsSomething, filter.ConjunctionType));

现在可能有更好的方法来做到这一点,所以我愿意接受任何完全避开这种方法的建议。

减少LambdaExpression签名

给定

var filter = new FilterObject()

应该是:

Expression<Func<MyObject, bool>> exp2 = 
             Expression.Lambda<Func<MyObject, bool>>(
                        Expression.Invoke(myExp, 
                                          myExp.Parameters[0], 
                                          Expression.Constant(filter)),
                        myExp.Parameters[0]);

Expression.Invoke将调用另一个表达式,并将新表达式的第一个参数作为第一个参数传递,并将带有过滤器的Expression.Constant作为第二个参数传递。

您是否尝试将Currying与Expression树结合使用?

比调用Invoke更好的方法是直接使用ExpressionVisitor替换表达式树中的参数。您可以定义几个简单的扩展方法来简化这一过程。在这种情况下,他们可以应用表达式的第一个参数(您需要更改签名或调整签名以应用中间参数)。

用法:

      var applied = expr.Apply(constValueForFirstParameter);

在静态类中定义以下扩展方法:

public static Expression<Func<U, V, bool>> Apply<T, U, V>(this Expression<Func<T, U, V, bool>> input, T value)
{
    var swap = new ExpressionSubstitute(input.Parameters[0], Expression.Constant(value));
    var lambda = Expression.Lambda<Func<U, V, bool>>(swap.Visit(input.Body), input.Parameters[1], input.Parameters[2]);
    return lambda;
}
public static Expression<Func<U, bool>> Apply<T, U>(this Expression<Func<T, U, bool>> input, T value)
{
    var swap = new ExpressionSubstitute(input.Parameters[0], Expression.Constant(value));
    var lambda = Expression.Lambda<Func<U, bool>>(swap.Visit(input.Body), input.Parameters[1]);
    return lambda;
}
class ExpressionSubstitute : System.Linq.Expressions.ExpressionVisitor
{
    private readonly Expression from, to;
    public ExpressionSubstitute(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        if (node == from) return to;
        return base.Visit(node);
    }
}