如何在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 sampleList = new List(); 

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

我该如何实现这种灵活性?

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

有没有聪明的方法来做到这一点?

谢谢。

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

 var filters = new Dictiontionary(); IEnumerable 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>(eq, parameter); // And finally use the expression to filter the collection query = query.Where(lambdaExpression); } var filteredList = query.ToList(); 

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

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

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

您可以使用这样的条件构建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 ),您可以使用相同的样式实现它们。

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

 // create your sample list List sampleList = new List(); sampleList.Add(...) // create the filter Dictionary Filter = new Dictionary(); 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(); 

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

 public class SampleClass { public IDictionary Properties { get; } } private static IList FilterList(IList list, params Tuple[] 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子句。