使用LINQ过滤集合

假设我们有一组Person对象

class Person { public string PersonName {get;set;} public string PersonAddress {get;set;} } 

并在代码定义集合中的某处

 List pesonsList = new List(); 

我们需要一个filter,需要过滤集合并将结果返回给最终用户。 假设我们有一个Filter类型对象的集合

 class Filter { public string FieldName {get;set;} public string FilterString {get;set;} } 

在我们的代码中的某个地方

 List userFilters = new List(); 

因此,我们需要通过userFilters集合中定义的filter来过滤personsList集合的内容。 Filter.FieldName ==“PersonName”||的位置 Filter.FieldName ==“PersonAddress” 。 我怎样才能以酷炫的方式使用LINQ呢? 像switch这样的解决方案,或者我认为,personList上的扩展方法可以从FiledName确定要查看的Person的属性。 别的什么? 有点棘手:)谢谢。

您可以使用Expression类构建lambda表达式以创建正确的谓词。

 public static Expression> CreateFilterExpression( IEnumerable filters) { ParameterExpression param = Expression.Parameter(typeof(TInput), ""); Expression lambdaBody = null; if (filters != null) { foreach (Filter filter in filters) { Expression compareExpression = Expression.Equal( Expression.Property(param, filter.FieldName), Expression.Constant(filter.FilterString)); if (lambdaBody == null) lambdaBody = compareExpression; else lambdaBody = Expression.Or(lambdaBody, compareExpression); } } if (lambdaBody == null) return Expression.Lambda>(Expression.Constant(false)); else return Expression.Lambda>(lambdaBody, param); } 

使用此辅助方法,您可以在任何IQueryable类上创建扩展方法,因此这适用于每个LINQ后端:

 public static IQueryable Where(this IQueryable source, IEnumerable filters) { return Queryable.Where(source, CreateFilterExpression(filters)); } 

…你可以这样打电话:

 var query = context.Persons.Where(userFilters); 

如果你也想支持IEnumerable集合,你需要使用这个额外的扩展方法:

 public static IEnumerable Where(this IEnumerable source, IEnumerable filters) { return Enumerable.Where(source, CreateFilterExpression(filters).Compile()); } 

请注意,这仅适用于字符串属性。 如果要对字段进行过滤,则需要将Expression.Property更改为Expression.Field (或MakeMemberAccess ),如果需要支持除字符串属性之外的其他类型,则必须向Expression.Constant提供更多类型信息Expression.Constant方法的Expression.Constant部分。

你可以通过反思来做到这一点:

 IQueryable filteredPersons = personsList.AsQueryable(); Type personType = typeof(Person); foreach(Filter filter in userFilters) { filteredPersons = filteredPersons.Where(p => (string)personType.InvokeMember(filter.FieldName, BindingFlags.GetProperty, null, p, null) == filter.FilterString); } 

(未编译,但这应该是正确的轨道)

你能不能这样做

 personList.Where(x => x.PersonName == "YourNameHere").ToList() ? 

我会向Filter类添加一个方法来检查filter是否满足:

 class Filter { public string FieldName {get;set;} public string FilterString {get;set;} public bool IsSatisfied(object o) { return o.GetType().GetProperty(FieldName).GetValue(o, null) as string == FilterString; } 

然后你可以像这样使用它:

 var filtered_list = personsList.Where(p => userFilters.Any(f => f.IsSatisfied(p)));