Как отфильтровать список на основе общего свойства - PullRequest
0 голосов
/ 08 мая 2019

Я пытаюсь удалить здесь жесткое кодирование при использовании LINQ. В основном у меня есть 10 свойств и на основе выбранного свойства я хочу отфильтровать список. Может кто-нибудь помочь мне удалить этот вид жесткого кодирования, есть ли способ получить информацию о свойстве на основе строкового значения "propertyName" и использовать его при фильтрации списка. Ниже приведен код для справки Пожалуйста, дайте мне знать, если мой вопрос имеет смысл. Заранее спасибо за помощь.

if (propertyName == "Property1")
                {
                    FilteredList = CurrentList.Where(x => x.property1== propertyValue.ToString()).ToList();
                }
                else if (propertyName == "Property2")
                {
                    FilteredList = CurrentList.Where(x => x.property2== propertyValue.ToString()).ToList();
                }

Ответы [ 2 ]

1 голос
/ 08 мая 2019

а. Отражение (если значения propertyName соответствуют фактическим именам свойств)

var t = typeof(...your type...);
var pi = t.GetProperty(propertyName);

CurrentFilterList = AfterFilterList
      .Where(x => pi.GetValue(x).ToString() == propertyValue)
      .ToList();

б. Если имена свойств не совпадают, вы можете попробовать это:

var funcs = new Dictionary<string, Func<your_type, object>> 
{
   {"Company", v => v.Company},
   {"InspectionUnit", v => v.InspectionUnit}
};

var f = funcs[propertyName];
CurrentFilterList = AfterFilterList
   .Where(x => f(x) == propertyValue.ToString()).ToList();

Код может быть неточным, но должен показать идею. № 2 должен иметь лучшую производительность.

КСТАТИ funcs также можно построить динамически, используя рефлексию - просто перебирайте все реквизиты и создавайте функции / выражения на лету.

0 голосов
/ 08 мая 2019

Вот функция, которая создает условие Where без отражения. Просто для иллюстрации, если имя свойства не распознано, оно возвращает условие, которое всегда возвращает истину - другими словами, без фильтра. Исключение может иметь больше смысла в ответ на нераспознанный ввод.

private Func<Thing, bool> GetCondition(string propertyName, string propertyValue)
{
    switch (propertyName)
    {
        case "Company":
            return thing => thing.Company == propertyValue;
        case "InspectionUnit":
            return thing => thing.InspectionUnit == propertyValue;
        default: return thing => true;
    }
}

Вот версия, которая использует отражение. Пока мы идем по этому маршруту, нет необходимости ограничивать свойство значениями string. Это может быть что угодно, пока реализован Equals, что будет верно для строк и типов значений.

private Func<Thing, bool> GetCondition<TSourceType, TPropertyType>
    (string propertyName, TPropertyType propertyValue)
{
    var property = typeof(TSourceType).GetProperty(
        propertyName, BindingFlags.Instance | BindingFlags.Public);
    if (property?.PropertyType != typeof(TPropertyType))
        return thing => true; // or throw an exception.
    return thing => property.GetValue(thing).Equals(propertyValue);
}

Для производительности было бы полезно сохранить отраженное свойство во что-то вроде Dictionary<Type, Dictionary<string, PropertyInfo>>, чтобы для любого заданного типа и имени свойства вы могли искать его вместо повторения отражения.

Между этими двумя я бы склонялся к , а не , используя отражение в вашем сценарии, если вы действительно просто смотрите на несколько возможных значений и имеете дело с известными типами.

Теперь использование будет

необщего / без отражения

var condition = GetCondition(propertyName, propertyValue);
var filtered = unfiltered.Where(condition);

общее / отражения

var condition = GetCondition<Thing, string>(propertyName, propertyValue);
var filtered = unfiltered.Where(condition);

Когда я упоминаю о сохранении свойств в словаре, это выглядит примерно так:

private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> _properties = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

private PropertyInfo GetProperty(Type sourceType, string propertyName)
{
    if(!_properties.ContainsKey(sourceType))
        _properties.Add(sourceType, new Dictionary<string, PropertyInfo>());
    if (_properties[sourceType].ContainsKey(propertyName))
        return _properties[sourceType][propertyName];
    var property = sourceType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
    _properties[sourceType].Add(propertyName, property);
    return property; // could be null;
}

Но опять же, это всего лишь пример. Это огромный перебор для сценария, который вы описываете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...