假设我有这样一个类:
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>();
我希望按SampleProperty1
和SampleProperty5
过滤该列表。下次我将使用SampleProperty3
或SampleProperty2
。我的意思是用户可以按他想要的任何属性进行过滤。
如何实现这种灵活性?
我不想写if语句与属性一样多,因为实际的属性数量要多得多。
是否有明智的方法可以做到这一点?
感谢。
答案 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
子句。