减少LambdaExpression签名

时间:2013-08-14 15:51:47

标签: c# expression-trees

我想不出一个更好的方式来解决这个问题,但我想要做的是通过处理一个实例来减少LambdaExpression从Expression<Func<MyObject, FilterObject, bool>>Expression<Func<MyObject, bool>>的签名。在评估LambdaExpression之前FilterObject

这是一个简单的例子:

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

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

2 个答案:

答案 0 :(得分:0)

给出

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 with Expression trees?

答案 1 :(得分:0)

比调用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);
    }
}