繁体   English   中英

如何根据通用属性过滤列表

[英]How to filter the list based on generic property

我正在尝试在使用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();
                }

一种。 反射(如果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应该有更好的性能。

BTW funcs刚刚经历的所有道具迭代,并即时创建funcs中/表情-可以动态使用反射以及建造。

这是一个无需反射即可创建Where条件的函数。 仅出于说明目的,如果无法识别属性名称,它将返回一个始终返回true的条件-换句话说,没有过滤器。 响应未识别的输入,异常可能更有意义。

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;
}

但是,这仅是一个例子。 对于您所描述的场景而言,这太过分了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM