Example
public static Expression<Func<T, bool>> GetExpression<T>(IList<QueryFilter> filters)
{
Expression exp = null;
// Represents a named parameter expression. {parm => parm.Name.Equals()}, it is the param part
// To create a ParameterExpression need the type of the entity that the query is against an a name
// The type is possible to find with the generic T and the name is fixed parm
ParameterExpression param = Expression.Parameter(typeof(T), "parm");
// It is good parctice never trust in the client, so it is wise to validate.
if (filters.Count == 0)
return null;
// The expression creation differ if there is one, two or more filters.
if (filters.Count != 1)
{
if (filters.Count == 2)
// It is result from direct call.
// For simplicity sake the private overloads will be explained in another example.
exp = GetExpression<T>(param, filters[0], filters[1]);
else
{
// As there is no method for more than two filters,
// I iterate through all the filters and put I in the query two at a time
while (filters.Count > 0)
{
// Retreive the first two filters
var f1 = filters[0];
var f2 = filters[1];
// To build a expression with a conditional AND operation that evaluates
// the second operand only if the first operand evaluates to true.
// It needed to use the BinaryExpression a Expression derived class
// That has the AndAlso method that join two expression together
exp = exp == null ? GetExpression<T>(param, filters[0], filters[1]) : Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1]));
// Remove the two just used filters, for the method in the next iteration finds the next filters
filters.Remove(f1);
filters.Remove(f2);
// If it is that last filter, add the last one and remove it
if (filters.Count == 1)
{
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0]));
filters.RemoveAt(0);
}
}
}
}
else
// It is result from direct call.
exp = GetExpression<T>(param, filters[0]);
// converts the Expression into Lambda and retuns the query
return Expression.Lambda<Func<T, bool>>(exp, param);
}