使用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)));