Reputation: 2975
I want to compose the results of two Linq Expressions. They exist in the form
Expression<Func<T, bool>>
So the two that I want to compose are essentially delegates on a parameter (of type T) that both return a boolean. The result I would like composed would be the logical evaluation of the booleans. I would probably implement it as an extension method so my syntax would be something like:
Expression<Func<User, bool>> expression1 = t => t.Name == "steve";
Expression<Func<User, bool>> expression2 = t => t.Age == 28;
Expression<Func<User, bool>> composedExpression = expression1.And(expression2);
And later on in my code I want to evaluate the composed expression
var user = new User();
bool evaluated = composedExpression.Compile().Invoke(user);
I have poked around with a few different ideas but I fear that it is more complex than I had hoped. How is this done?
Upvotes: 17
Views: 11494
Reputation: 123966
Here is an example:
var user1 = new User {Name = "steve", Age = 28};
var user2 = new User {Name = "foobar", Age = 28};
Expression<Func<User, bool>> expression1 = t => t.Name == "steve";
Expression<Func<User, bool>> expression2 = t => t.Age == 28;
var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
var result = Expression.Lambda<Func<User, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
Console.WriteLine(result.Compile().Invoke(user1)); // true
Console.WriteLine(result.Compile().Invoke(user2)); // false
You can reuse this code via extension methods:
class User
{
public string Name { get; set; }
public int Age { get; set; }
}
public static class PredicateExtensions
{
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,Expression<Func<T, bool>> expression2)
{
InvocationExpression invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
}
}
class Program
{
static void Main(string[] args)
{
var user1 = new User {Name = "steve", Age = 28};
var user2 = new User {Name = "foobar", Age = 28};
Expression<Func<User, bool>> expression1 = t => t.Name == "steve";
Expression<Func<User, bool>> expression2 = t => t.Age == 28;
var result = expression1.And(expression2);
Console.WriteLine(result.Compile().Invoke(user1));
Console.WriteLine(result.Compile().Invoke(user2));
}
}
Upvotes: 21