Skip to content

Instantly share code, notes, and snippets.

@ionuttamas
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ionuttamas/5c8cc546e3b27ecd977d to your computer and use it in GitHub Desktop.
Save ionuttamas/5c8cc546e3b27ecd977d to your computer and use it in GitHub Desktop.
Runtime expression builder
public static IEnumerable<T> WhereByFilter<T>(this IEnumerable<T> collection, Expression filter)
{
dynamic dynamicFilter = filter;
dynamic function = dynamicFilter.Compile();
dynamic result = Enumerable.Where(collection, function);
return result;
}
public class ExpressionQuery
{
private const char PropertySeparator = '.';
private const string Parameter = "x";
private Expression _accumulator;
private Type _type;
private ParameterExpression _parameter;
private ExpressionQuery()
{
_accumulator = Expression.Constant(true);
}
public static ExpressionQuery Empty
{
get { return new ExpressionQuery(); }
}
public Expression<Func<T, bool>> GetResult<T>()
{
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(_accumulator, _parameter);
return lambda;
}
public Expression GetResult()
{
Type delegateType = typeof(Func<,>).MakeGenericType(_type, typeof(bool));
LambdaExpression lambda = Expression.Lambda(delegateType, _accumulator, _parameter);
return lambda;
}
public ExpressionQuery WithType<T>()
{
_type = typeof (T);
_parameter = Expression.Parameter(_type, Parameter);
return this;
}
public ExpressionQuery WithType(Type type)
{
_type = type;
_parameter = Expression.Parameter(_type, Parameter);
return this;
}
public ExpressionQuery AndIsTrue(string property)
{
Expression source = GetExpressionBody(property);
UnaryExpression checkExpression = Expression.IsTrue(source);
_accumulator = Expression.AndAlso(_accumulator, checkExpression);
return this;
}
public ExpressionQuery AndIsFalse(string property)
{
Expression source = GetExpressionBody(property);
UnaryExpression checkExpression = Expression.IsFalse(source);
_accumulator = Expression.AndAlso(_accumulator, checkExpression);
return this;
}
public ExpressionQuery AndContains(string property, string value)
{
MethodCallExpression methodExpression = GetExpressionMethod(property, "Contains", value);
_accumulator = Expression.AndAlso(_accumulator, methodExpression);
return this;
}
public ExpressionQuery AndStartsWith(string property, string value)
{
MethodCallExpression methodExpression = GetExpressionMethod(property, "StartsWith", value);
_accumulator = Expression.AndAlso(_accumulator, methodExpression);
return this;
}
public ExpressionQuery AndGreaterThan(string property, int value)
{
Expression source = GetExpressionBody(property);
ConstantExpression targetValue = Expression.Constant(value, typeof (int));
BinaryExpression comparisonExpression = Expression.GreaterThan(source, targetValue);
_accumulator = Expression.AndAlso(_accumulator, comparisonExpression);
return this;
}
public ExpressionQuery AndLessThan(string property, int value)
{
Expression source = GetExpressionBody(property);
ConstantExpression targetValue = Expression.Constant(value, typeof (int));
BinaryExpression comparisonExpression = Expression.LessThan(source, targetValue);
_accumulator = Expression.AndAlso(_accumulator, comparisonExpression);
return this;
}
public ExpressionQuery AndEqualTo(string property, int value)
{
Expression source = GetExpressionBody(property);
ConstantExpression targetValue = Expression.Constant(value, typeof (int));
BinaryExpression comparisonExpression = Expression.Equal(source, targetValue);
_accumulator = Expression.AndAlso(_accumulator, comparisonExpression);
return this;
}
public ExpressionQuery AndByFunction(string property, string functionName, object value)
{
MethodCallExpression methodExpression = GetExpressionMethod(property, functionName, value);
_accumulator = Expression.AndAlso(_accumulator, methodExpression);
return this;
}
private Expression GetExpressionBody(string property)
{
Expression body = _parameter;
if (!property.Contains(PropertySeparator.ToString()))
{
body = Expression.PropertyOrField(body, property);
}
else
{
foreach (string member in property.Split(PropertySeparator))
body = Expression.PropertyOrField(body, member);
}
return body;
}
private MethodCallExpression GetExpressionMethod<T>(string property, string methodName, T value)
{
MethodInfo method = typeof (string).GetMethod(methodName, new[] {typeof (string)});
Expression source = GetExpressionBody(property);
ConstantExpression targetValue = Expression.Constant(value, typeof (string));
MethodCallExpression methodExpression = Expression.Call(source, method, targetValue);
return methodExpression;
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public double UnitPrice { get; set; }
public Supplier Supplier { get; set; }
}
public class Supplier
{
public string Name { get; set; }
public string Company { get; set; }
public string Phone { get; set; }
}
var result = ExpressionQuery
.Empty
.WithType<Product>()
.AndEqualTo("Id", 1)
.AndContains("Name", "iPhone")
.AndContains("Supplier.Name", "Plus")
.GetResult();
var products = new List<Product>();
var filteredProducts = products.WhereByFilter(result);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment