Это создаст лямбда-выражение, которое будет пересекать свойства между родовым c типом T
и классом Filter
и сравнивать их на равенство; каждая отдельная пара свойств объединяется с условием AND.
public static IEnumerable<T> ModelPagination<T>(F filter)
{
// all properties which are in the fiter class also present in the generic type T
var commonPropertyNames = filter
.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(x => x.Name)
.Intersect(
typeof(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(x => x.Name)
);
var argumentExpression = Expression.Parameter(typeof(T), "x");
var filterConstantExpression = Expression.Constant(filter);
// build the expression
var expression = (BinaryExpression)null;
foreach (var propertyName in commonPropertyNames)
{
var filterPropertyExpression = Expression.Property(filterConstantExpression, propertyName);
var equalExpression = Expression.Equal(
Expression.Property(argumentExpression, propertyName),
filterPropertyExpression
);
var nullCheckExpression = Expression.Equal(
filterPropertyExpression,
Expression.Constant(null)
);
var orExpression = Expression.OrElse(equalExpression, nullCheckExpression);
if (expression == null)
{
expression = orExpression;
}
else
{
expression = Expression.AndAlso(expression, orExpression);
}
}
var lambda = Expression.Lambda<Func<T, bool>>(expression, argumentExpression);
return dbContext.Entry<T>().Where(lambda).ToList();
}
Если у вас есть тип T
как этот { FirstName, LastName }
и Filter
класс как этот { FirstName }
, он создаст следующее выражение
x => x.FirstName == filter.FirstName || filter.FirstName == null
Если у вас есть тип T
как этот { FirstName, LastName }
и Filter
класс, подобный этому { FirstName, LastName }
, создаст следующее выражение
x => (x.FirstName == filter.FirstName || filter.FirstName == null)
&& (x.LastName == filter.LastName || filter.LastName == null)
Это сделает работу, но есть место для оптимизации.