Skip to content

Instantly share code, notes, and snippets.

@enisn
Created April 16, 2020 19:53
Show Gist options
  • Select an option

  • Save enisn/3a617f11dd2b375fe7fb6927fe360337 to your computer and use it in GitHub Desktop.

Select an option

Save enisn/3a617f11dd2b375fe7fb6927fe360337 to your computer and use it in GitHub Desktop.
Challenge #1 - Solution 2 - FilterBase.cs
public class FilterBase : IFilter
{
public virtual CombineType CombineWith { get; set; }
public virtual IQueryable<TEntity> ApplyFilterTo<TEntity>(IQueryable<TEntity> query)
{
var parameter = Expression.Parameter(typeof(TEntity), "x");
var exp = BuildExpression(typeof(TEntity), parameter);
if (exp == null)
return query;
var lambda = Expression.Lambda<Func<TEntity, bool>>(exp, parameter);
return query.Where(lambda);
}
public virtual Expression BuildExpression(Type entityType, Expression body)
{
Expression finalExpression = null;
var _type = this.GetType();
foreach (var entityProperty in entityType.GetProperties())
{
try
{
var filterProperty = _type.GetProperty(entityProperty.Name);
if (filterProperty == null)
continue;
var val = filterProperty.GetValue(this);
if (val == null)
continue;
var attribute = filterProperty.GetCustomAttribute<FilteringOptionsBaseAttribute>(false);
if (attribute != null)
{
var expression = attribute.BuildExpression(body, entityProperty, val);
finalExpression = Combine(finalExpression, expression);
continue;
}
if (val is IFilter filter)
{
if (typeof(ICollection).IsAssignableFrom(entityProperty.PropertyType) || (entityProperty.PropertyType.IsConstructedGenericType && typeof(IEnumerable).IsAssignableFrom(entityProperty.PropertyType)))
{
var type = entityProperty.PropertyType.GetGenericArguments().FirstOrDefault();
var prop = Expression.Property(body, entityProperty.Name);
var parameter = Expression.Parameter(type, "a");
var methodInfo = typeof(Enumerable).GetMethods().LastOrDefault(x => x.Name == "Any");
var method = methodInfo.MakeGenericMethod(type);
var query = filter.BuildExpression(type, body: parameter);
var lambda = Expression.Lambda(query, parameter);
var expression = Expression.Call(
method: method,
instance: null,
arguments: new Expression[] { prop, lambda }
);
finalExpression = Combine(finalExpression, expression);
continue;
}
else
{
var parameter = Expression.Property(body, entityProperty.Name);
var expression = filter.BuildExpression(entityProperty.PropertyType, parameter);
finalExpression = Combine(finalExpression, expression);
continue;
}
}
if (val is IFilterableType filterableProperty)
{
var expression = filterableProperty.BuildExpression(body, entityProperty, val);
finalExpression = Combine(finalExpression, expression);
}
else
{
var comparison = Expression.Equal(
Expression.Property(body, entityProperty.Name),
Expression.Constant(val)
);
finalExpression = Combine(finalExpression, comparison);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex?.ToString());
}
}
return finalExpression;
}
private protected virtual Expression Combine(Expression body, Expression extend)
{
if (body == null)
return extend;
if (extend == null)
return body;
switch (CombineWith)
{
case CombineType.And:
return Expression.And(body, extend);
case CombineType.Or:
return Expression.Or(body, extend);
default:
return extend;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment