Skip to content

Instantly share code, notes, and snippets.

@teleginski
Last active April 29, 2021 17:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save teleginski/ad36a68537f4151ecf47971c28e7139b to your computer and use it in GitHub Desktop.
Save teleginski/ad36a68537f4151ecf47971c28e7139b to your computer and use it in GitHub Desktop.
C# .NET - Expression Builder - Dynamic Filter - Dynamic Where
public static class ExpressionBuilder
{
private static readonly MethodInfo containsMethod = typeof(string).GetMethod("Contains");
private static readonly MethodInfo toLowerMethod = typeof(string).GetMethod("ToLower", new Type[0] { });
public static Func<T, bool> GetExpression<T>(IList<Filter> filters)
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "t");
Expression expression = null;
if (filters == null || !filters.Any())
expression = Expression.Equal(Expression.Default(typeof(T)), Expression.Default(typeof(T)));
else
{
foreach (var filter in filters)
{
if (expression == null)
expression = GetExpression<T>(parameter, filter);
else
expression = Expression.AndAlso(expression, GetExpression<T>(parameter, filter));
}
}
return Expression.Lambda<Func<T, bool>>(expression, parameter).Compile();
}
private static Expression GetExpression<T>(ParameterExpression parameter, Filter filter)
{
MemberExpression member = Expression.PropertyOrField(parameter, filter.Property);
UnaryExpression constant = GetUnary(member, filter);
switch (filter.Operator)
{
case Operator.Equals:
if (member.Type == typeof(string))
return Expression.Equal(Expression.Call(member, toLowerMethod), constant);
else
return Expression.Equal(member, constant);
case Operator.NotEquals:
if (member.Type == typeof(string))
return Expression.NotEqual(Expression.Call(member, toLowerMethod), constant);
else
return Expression.NotEqual(member, constant);
case Operator.GreaterThan:
return Expression.GreaterThan(member, constant);
case Operator.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(member, constant);
case Operator.LessThan:
return Expression.LessThan(member, constant);
case Operator.LessThanOrEqual:
return Expression.LessThanOrEqual(member, constant);
case Operator.Contains:
if (member.Type == typeof(string))
return Expression.Call(Expression.Call(member, toLowerMethod), containsMethod, constant);
else
return Expression.Call(member, containsMethod, constant);
}
return null;
}
private static UnaryExpression GetUnary(MemberExpression member, Filter filter)
{
if (filter.Value is string)
return Expression.Convert(Expression.Constant(filter.Value.ToString().ToLower().Trim()), member.Type);
if (filter.Value == null)
return Expression.Convert(Expression.Constant(filter.Value), member.Type);
if (member.Type.Equals(typeof(DateTime)) || member.Type.Equals(typeof(DateTime?)))
return Expression.Convert(Expression.Constant(DateTime.Parse(filter.Value.ToString())), member.Type);
else
return Expression.Convert(Expression.Constant(filter.Value), member.Type);
}
}
public class Filter
{
public string Property { get; set; }
public Operator Operator { get; set; }
public object Value { get; set; }
}
public enum Operator
{
Contains,
Equals,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
NotEquals
}
// How to use
var predicate = ExpressionBuilder.GetExpression<Consumer>(filters);
var query = Consumer.Where(predicate).ToList();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment