#c# #asp.net-core #generics #predicate
Вопрос:
У меня есть код предиката, который отлично работает, но я хочу сократить свой код, преобразовать его в универсальный и использовать в своем репозитории
public abstract class RequestParameters
{
const int maxPageSize = 5;
public int PageNumber { get; set; } = 1;
private int _pageSize = 10;
public int PageSize
{
get
{
return _pageSize;
}
set
{
_pageSize = (value > maxPageSize) ? maxPageSize : value;
}
}
public string OrderBy { get; set; }
public string Fields { get; set; }
}
а это моя модель поиска сотрудников
public class EmployeeSearchModel : RequestParameters
{
public EmployeeSearchModel()
{
OrderBy = "name";
}
public string Name { get; set; }
public int Age { get; set; }
public string Position { get; set; }
public Expression<System.Func<Employee, bool>> Go()
{
var predicate = PredicateBuilder.True<Employee>();
if (!string.IsNullOrEmpty(Name))
{
predicate = predicate.And(i => i.Name.ToLower().Contains(Name.ToLower()));
}
if (!string.IsNullOrEmpty(Position))
{
predicate = predicate.And(i => i.Position.ToLower().Contains(Position.ToLower()));
}
return predicate;
}
}
и это мое хранилище
public async Task<PagedList<Employee>> GetEmployeesAsyncExp(EmployeeSearchModel employeeParameters)
{
Expression f = employeeParameters.Go();
var employees = await FindByCondition(employeeParameters.Go())
.OrderBy(e => e.Name)
.ToListAsync()....
….
и теперь я хочу изменить его на что-то общее, как это:
public class EmployeeSearchModel<T> : RequestParameters ...
Комментарии:
1. Как универсальная версия должна знать свойство Name или Position для универсального типа? В какой-то момент вы должны выполнить свое условие поиска.
Ответ №1:
Ну, здесь нет реального вопроса, и много недостающей информации, а также дезинформации. Я предполагаю, что вы захотите заменить класс «Сотрудник», чтобы также фильтровать другие классы с помощью вашей части SearchModel. Поэтому «EmployeeSearchModel» неверен, так как он все еще содержит Сотрудника.
С другой стороны, ваш метод использует некоторые специфические для сотрудника части, такие как Имя или Возраст, и если ваши другие классы также не содержат Возраст и имя, это не может использоваться в качестве универсального метода.
Лучшее, что вы можете сделать для повторного использования вашей поисковой модели, — это изменить ее на абстрактный класс и позволить EmployeeSearchModel наследовать это:
public abstract class SearchModel<T> : RequestParameters
{
public abstract Expression<System.Func<T, bool>> Go();
}
public class EmployeeSearchModel : SearchModel<Employee>
{
public EmployeeSearchModel()
{
OrderBy = "name";
}
public string Name { get; set; }
public int Age { get; set; }
public string Position { get; set; }
public override Expression<Func<Employee, bool>> Go()
{
var predicate = PredicateBuilder.True<Employee>();
if (!string.IsNullOrEmpty(Name))
{
predicate = predicate.And(i => i.Name.ToLower().Contains(Name.ToLower()));
}
if (!string.IsNullOrEmpty(Position))
{
predicate = predicate.And(i => i.Position.ToLower().Contains(Position.ToLower()));
}
return predicate;
}
}
Затем вы можете использовать его также для поиска с другими классами, такими как компания:
public class CompanySearchModel : SearchModel<Company>
{
public string Department {get; set;}
public override Expression<Func<Company, bool>> Go()
{
var predicate = PredicateBuilder.True<Company>();
if (!string.IsNullOrEmpty(Department))
{
predicate = predicate.And(x => x.Department.ToLower().Contains(Department.ToLower()));
}
}
}
Комментарии:
1. основная проблема заключается в следующем коде: открытое выражение переопределения<Функция<Сотрудник, bool><Сотрудник, bool>> Go() { …. потому что, если класс имеет много свойств, я должен повторить этот код : если (!строка. IsNullOrEmpty(Имя)) { предикат = предикат. И(я => i.Name. ToLower().Содержит(Имя. ToLower())); } итак, есть ли способ получить список свойств внутри класса, а затем с помощью цикла выполнить проверку и назначить эту строку if (!). IsNullOrEmpty(Отдел)) { предикат = предикат.И(x => x.Отдел. ТоЛоуэр().Продолжение……
2. @Ali Вы можете использовать отражение и метод GetProperties. Есть несколько вопросов по stackoverflow, просто найдите его. Я не проверял его, и он может не работать с предикатом, но вот фрагмент, который получает все общедоступные свойства типа string:
var props = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); for (var i = 0; i < props.Length; i ) { if (props[i].PropertyType == typeof(string) amp;amp; props[i].GetGetMethod(true).IsPublic amp;amp; props[i].CanRead) { // do your predicate logic here } }
3. так как я могу использовать реквизиты после IF как : предикат = предикат. И(я => i.Name. ToLower().Содержит(Имя. ToLower ())); ?
4. Вы можете оценить это так:
props[i].GetValue(yourClass, null).ToString().ToLower() == compareableText.ToLower()