2

I'm trying to refactor a complex Linq query. I would like to know if there's a way that we can do something like this : Suppose that we have two expressions:

Expression<Func<object,bool>> exp1=....;
Expression<Func<object,bool>> exp2=....;

Expression<Func<object,bool>> exp3=exp1 || exp2;
Beatles1692
  • 5,214
  • 34
  • 65
  • Would the [Expression.OrElse](http://msdn.microsoft.com/en-us/library/bb353063.aspx) method work for that case? – Dirk Jun 13 '13 at 11:34

2 Answers2

3

Basically you need to re-write one of the trees, so that you can combine the expressions. Fortunately ExpressionVisitor helps us:

static void Main()
{
    Expression<Func<object, bool>> exp1 = x => ((string)x).StartsWith("a");
    Expression<Func<object, bool>> exp2 = y => ((string)y).StartsWith("b");
    // the two expressions here are purely for illustration

    var exp3 = Combine(exp1, exp2, Expression.OrElse); // i.e. ||
    var exp4 = Combine(exp1, exp2, Expression.AndAlso); // i.e. &&
}
static Expression<Func<TValue, TResult>> Combine<TValue, TResult>(
    Expression<Func<TValue, TResult>> left,
    Expression<Func<TValue, TResult>> right,
    Func<Expression, Expression, BinaryExpression> combination)
{
    // rewrite the body of "right" using "left"'s parameter in place
    // of the original "right"'s parameter
    var newRight = new SwapVisitor(right.Parameters[0], left.Parameters[0])
                        .Visit(right.Body);
    // combine via && / || etc and create a new lambda
    return Expression.Lambda<Func<TValue, TResult>>(
        combination(left.Body, newRight), left.Parameters);
}
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);
    }
}

Note that this also allows other arbitrary uses, for example:

Expression<Func<object, int>> exp1 = x => x.GetHashCode();
Expression<Func<object, int>> exp2 = y => y.ToString().Length;

var exp3 = Combine(exp1, exp2, Expression.Add);
// which is: x => x.GetHashCode() + x.ToString().Length;

I can think of no practical use for that ... but it is there ;p

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

You can use Dynamic Linq Query or PredicateBuilder.

Loetn
  • 3,832
  • 25
  • 41
  • Have you used PredicateBuilder before ? It's getting an error that says "The LINQ expression node type 'Invoke' is not supported in LINQ to Entities." – Beatles1692 Jun 13 '13 at 11:59
  • 1
    Yes, I have. :) The answer to your question can be found here: http://stackoverflow.com/a/11313924/2478357 – Loetn Jun 13 '13 at 12:01