This is the second part of an update about Mono.Linq.Expressions
, a tiny helper library to complement the System.Linq.Expressions namespace for .net 4 and Mono.
The first part is about fluent creation of expression trees
### Combining expression trees together
I keep reading questions on StackOverflow
about this. How to combine two lambda expression together? If we have:
Expression<Func<User, bool>> isUserOver18 = u => u.Age >= 18;
Expression<Func<User, bool>> isFemaleUser = u => u.Gender == Gender.Female;
If we want to combine this lambda expression with a “and” logical expression, the natural way would be to write:
Expression<Func<User, bool>> isFemaleUserOver18 = u =>
isUserOver18(u) && isFemaleUser(u);
This works just fine if you compile the expression into a delegate to actually execute this code. But most of the time questions of StackOverflow are about using the resulting lambda expression to create a query for LINQ to a database provider, which will analyze the expression tree and create an according SQL request.
By combining expression trees this way, the LINQ provider may or may not be unable to turn the two invocations into actual SQL.
That's one of the reason I wrote about an updated PredicateBuilder
. The obvious solution is to inline the two combined representation of lambda expressions into a new lambda expression tree.
The update of Mono.Linq.Expressions
comes with a new type, CombineExtensions
, which exposes extension methods that you can use to combine fully created (into lambda expressions) expression trees.
Using those, combining the two expression trees is as simple as:
Expression<Func<User, bool>> isFemaleUserOver18 = isUserOver18.Combine(
(left, right) => left.AndAlso(right));
And indeed, if you print the code representation of this expression tree, you'll have both lambda bodies inlined into another one:
user => user.Age >= 18 && user.Gender == Gender.Female
Or if you want to negate the boolean expression:
Expression<Func<User, bool>> isNotFemaleUserOver18 = isFemaleUserOver18.Combine(
e => e.Not());
The cool thing about those Combine extension methods is that they're completely generic, they don't work only on simple predicates. For instance, you can use those to chain constructions of mathematical expressions.