Last active
August 29, 2015 14:23
-
-
Save ionuttamas/5c8cc546e3b27ecd977d to your computer and use it in GitHub Desktop.
Runtime expression builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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