с прошлой недели мы столкнулись с подобной проблемой, вот идея, которую я только что предложил для нее. Я поделился этим с тобой.
interface IPerson
{
DateTime BirthDay { get; set; }
string City { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
}
interface IFilter { }
interface IPersonFilter : IFilter { }
class PersonFilter : IPersonFilter
{
public DateTime? BirthDay { get; set; }
public string City { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
static IQueryable<TSource> ApplyFilter<TSource, TFilter>(IQueryable<TSource> source, TFilter filter) where TFilter : IFilter
{
const BindingFlags bindingFlags = BindingFlags.Public|BindingFlags.Instance|BindingFlags.GetProperty;
var retval = source;
foreach (var filterProperty in filter.GetType().GetProperties(bindingFlags))
{
var elementParameter = Expression.Parameter(source.ElementType, "type");
var elementProperty = Expression.Property(elementParameter, filterProperty.Name);
var value = filterProperty.GetGetMethod().Invoke(filter, null);
if (value != null)
{
var constantValue = Expression.Constant(value, elementProperty.Type);
var expression = Expression.Equal(elementProperty, constantValue);
retval = retval.Where(Expression.Lambda<Func<TSource, bool>>(expression, elementParameter));
}
}
return retval;
}
так что идея в том, что у вас есть фильтр, в котором имена свойств фильтра совпадают с именами свойств объекта, для которого вы хотите запустить фильтр. и если значение свойства не равно нулю, я создаю для него выражение. Для простоты я создаю только Expression.Equal
выражения, но я думаю о его расширении.