Вот функция, которая создает условие 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;
}
Но опять же, это всего лишь пример. Это огромный перебор для сценария, который вы описываете.