Skip to content

Instantly share code, notes, and snippets.

@Vake93
Last active June 21, 2019 06:04
Show Gist options
  • Save Vake93/c098b5c990217a58e198edc097025d75 to your computer and use it in GitHub Desktop.
Save Vake93/c098b5c990217a58e198edc097025d75 to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using System.Linq.Expressions;
namespace Extensions
{
public static class PredicateBuilder
{
public enum CombinationLogic
{
AND,
OR
}
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
// S -> source type, Q -> query type
// Create Where Expression for source type using
// query type object which has same
// properties (by name and type*)
public static Expression<Func<S, bool>> BuildWhere<S, Q>(
Q query,
CombinationLogic combinationalLogic = CombinationLogic.AND)
{
var predicate = (combinationalLogic == CombinationLogic.OR) ?
False<S>() :
True<S>();
var queryProperties = typeof(Q).GetProperties();
var sourceProperties = typeof(S).GetProperties();
var expressionParameter = Expression.Parameter(typeof(S));
foreach (var property in queryProperties)
{
var propertyType = property.PropertyType;
var propertyValue = property.GetValue(query);
var sourceProperty = sourceProperties
.Where(p => p.Name == property.Name)
.FirstOrDefault();
if (propertyValue is null || sourceProperty is null)
{
continue;
}
//If the source has a value type prop and query
//waraps it as a nullable the unwarp the type
//and get the value
if (sourceProperty.PropertyType != propertyType &&
propertyType.IsGenericType &&
propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = Nullable.GetUnderlyingType(propertyType);
propertyValue = Convert.ChangeType(propertyValue, propertyType);
}
//check to see if the source prop type equals
//query prop type
if (sourceProperty.PropertyType != propertyType)
{
continue;
}
var expressionProperty = Expression.Property(expressionParameter, property.Name);
var expressionConstant = Expression.Constant(propertyValue, propertyType);
var expressionEqual = Expression.Equal(expressionProperty, expressionConstant);
var lambda = Expression.Lambda<Func<S, bool>>(expressionEqual, expressionParameter);
predicate = (combinationalLogic == CombinationLogic.OR) ?
Or(predicate, lambda) :
And(predicate, lambda);
}
return predicate;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment