如何在LINQ中过滤具有不同参数的列表

时间:2017-05-05 07:26:20

标签: c# linq

假设我有这样一个类:

public class SampleClass
{
    public string SampleProperty1 { get; set; }
    public string SampleProperty2 { get; set; }
    public string SampleProperty3 { get; set; }
    public string SampleProperty4 { get; set; }
    public string SampleProperty5 { get; set; }
}

我有一个这样的清单:

List<SampleClass> sampleList = new List<SampleClass>();

我希望按SampleProperty1SampleProperty5过滤该列表。下次我将使用SampleProperty3SampleProperty2。我的意思是用户可以按他想要的任何属性进行过滤。

如何实现这种灵活性?

我不想写if语句与属性一样多,因为实际的属性数量要多得多。

是否有明智的方法可以做到这一点?

感谢。

4 个答案:

答案 0 :(得分:1)

您可以使用这样的条件构建LINQ语句。

var query = sampleList;

if(shouldFilterProperty1)
{
    query = query.Where(x => x.SampleProperty1.Contains(SearchPattern1));
}
if(shouldFilterProperty2)
{
    query = query.Where(x => x.SampleProperty2.Contains(SearchPattern2));
}

var result = query.ToList();

这只是前两个属性的一个示例。如果您需要其他检查(不是Contains),您可以使用相同的样式实现它们。

答案 1 :(得分:1)

您可以为每个属性构建lambda表达式,并使用它过滤集合。 我们假设您有Dictionary个属性名称及其要过滤的值:

var filters = new Dictiontionary<string, object>();
IEnumerable<SampleClass> query = listOfSampleClasses;

// we will loop through the filters
foreach(filter in filters)
{
    // find the property of a given name
    var property = typeof(SampleClass).GetProperty(filter.Key, BindingFlags.Instance | BindingFlags.Public);
    if (property == null) continue;

    // create the ParameterExpression
    var parameter = Expression.Parameter(typeof(SampleClass));
    // and use that expression to get the expression of a property
    // like: x.SampleProperty1
    var memberExpression = Expression.Property(parameter, property);

    // Convert object type to the actual type of the property
    var value = Convert.ChangeType(filter.Value, property.PropertyType, CultureInfo.InvariantCulture);

    // Construct equal expression that compares MemberExpression for the property with converted value
    var eq = Expression.Equal(memberExpression, Expression.Constant(value));

    // Build lambda expresssion (x => x.SampleProperty == some-value)
    var lambdaExpression = Expression.Lambda<Func<SampleClass, bool>>(eq, parameter);

    // And finally use the expression to filter the collection
    query = query.Where(lambdaExpression);
}

var filteredList = query.ToList();

当然,您可以将该代码放在泛型方法中,并过滤任何类型的集合。

对于输入字典,包含两对:"SampleProperty1" - "foo""SampleProperty2" - "bar" 它会产生类似的东西:

listOfSampleClasses
    .Where(x => x.SampleProperty1 == "foo")
    .Where(x => x.SampleProperty2 == "bar");

答案 2 :(得分:1)

您可以找到要通过反射过滤的属性,并使用此方法构建LINQ查询。

// create your sample list
List<SampleClass> sampleList = new List<SampleClass>();
sampleList.Add(...) 

// create the filter
Dictionary<string, string> Filter = new Dictionary<string, string>();
Filter.Add("SampleProperty1", "SearchPattern1");
Filter.Add("SampleProperty5", "SearchPattern5");

// create the linq query
var query = sampleList.AsEnumerable();    
foreach(var filterItem in Filter)
{   
    // get the property you want to filter
    var propertyInfo = typeof(SampleClass).GetProperty(filterItem.Key);

    // add the filter to your query
    query = query.Where(x => (string)propertyInfo.GetValue(x) == filterItem.Value);
}

// execute the query
var resultList = query.ToList();

答案 3 :(得分:0)

如果您能够更改SampleClass课程的结构,那么您可以尝试以下内容:

public class SampleClass
{
    public IDictionary<string, string> Properties { get; }
}

private static IList<SampleClass> FilterList(IList<SampleClass> list,
                                             params Tuple<string, string>[] propertyNames)
{
    // No point filtering here.
    if (propertyNames == null)
    {
        return list; // or null/empty list if you want to match none as the default.
    }

    // Match All the property values supplied in the filter, you can change this to
    // Contains or string.Equals, etc. to suit your matching needs.
    return list.Where(x => propertyNames.All(p => x.Properties[p.Item1] == p.Item2))
               .ToList();
}

用法:

FilterList(sampleList,
           Tuple.Create("SampleProperty1", "Value1"),
           Tuple.Create("SampleProperty5", "Value5"));

这种方法的优点意味着您不需要大量的if语句来确定最初要求的Where子句。