结合两个linq表达式

时间:2014-02-14 10:06:16

标签: c# asp.net linq expression

我有两个linq表达式我想要组合但是我的代码给了我一个错误二元运算符并没有为类型'System.Func`2[Web.Entities.Customer,System.Boolean]''System.Func`2[Web.Entities.Customer,System.Boolean]'定义。

我有两个表达式例如...

 Expression<Func<Customer, bool>> filter = c => c.Active;
 Expression<Func<Customer, bool>> filterz = c => c.Visible;
然后我将它们组合起来

 filter = Expression.Lambda<Func<Customer, bool>>(Expression.And(filter, filterz));

有关此问题的任何帮助吗?

感谢....

这是在下面的答案中给出的更新代码。

public class SwapVisitor : ExpressionVisitor
{

    private readonly Expression from, to;
    public SwapVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }

    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

filter = Expression.Lambda<Func<Customer, bool>>(Expression.AndAlso(
                        new SwapVisitor(filter.Parameters[0], filterz.Parameters[0]).Visit(filter.Body), filterz.Body), filterz.Parameters)

3 个答案:

答案 0 :(得分:3)

Expression<Func<Customer, bool>> filter1 = c => c.Active;
Expression<Func<Customer, bool>> filter2 = c => c.Visible;

var parameter = Expression.Parameter(typeof(Customer), "x");

var filter = Expression.Lambda<Func<Customer, bool>>(
                Expression.AndAlso(
                    Expression.Invoke(filter1,parameter),
                    Expression.Invoke(filter2,parameter)
                ),parameter
            );

答案 1 :(得分:2)

如果你在每个过滤器中使用相同的Customer,那么你可以尝试:

        Expression<Func<Customer, bool>> filter = c => c.Active;
        Expression<Func<Customer, bool>> filter2 = c => c.Visible;

        var body = Expression.AndAlso(filter.Body, Expression.Invoke(filter2, filter.Parameters[0]));

        filter = Expression.Lambda<Func<Customer, bool>>(body, filter.Parameters);
        var applyFilter = filter.Compile();

        var customer = new Customer() { Visible = true, Active = true};
        Console.WriteLine(applyFilter(customer));

        customer.Active = false;
        Console.WriteLine(applyFilter(customer));

        customer.Visible = false;
        Console.WriteLine(applyFilter(customer));

答案 2 :(得分:1)

您已经可以在存储库中使用表达式而无需外部组合它们:

var yourContext = getContext();
var filtered = yourContext.Where(filter).Where(filter2);

在这种情况下,组合是不必要的,这种方法可以在不影响效率的情况下发挥作用。

如果您需要合并:

尝试使用以下访问者帮助:

public class ReplacementVisitor : System.Linq.Expressions.ExpressionVisitor
{
    private readonly Expression _oldExpr;
    private readonly Expression _newExpr;
    public ReplacementVisitor(Expression oldExpr, Expression newExpr)
    {
        _oldExpr = oldExpr;
        _newExpr = newExpr;
    }

    public override Expression Visit(Expression node)
    {
        if (node == _oldExpr)
            return _newExpr;
        return base.Visit(node);
    }
}

我们需要它,因为您的过滤表达式使用不同的参数实例。对于组合,我们需要它们使用相同的参数实例。本课程帮助我们完成以下任务:

Expression<Func<Customer, bool>> filter = c => c.Active;
Expression<Func<Customer, bool>> filterz = c => c.Visible;

var newParameter = Expression.Parameter(typeof(Customer), "x");
var visitor1 = new ReplacementVisitor(filter.Parameters[0], newParameter);
var visitor2 = new ReplacementVisitor(filterz.Parameters[0], newParameter);

var newLambda = Expression.Lambda(
    Expression.AndAlso(
        visitor1.Visit(filter.Body),
        visitor2.Visit(filterz.Body)
    ),
    newParameter
);