过滤收集与LINQ [英] Filtering collection with LINQ
问题描述
让我们说我们有Person对象的集合
Let's say we have a collection of Person objects
class Person
{
public string PersonName {get;set;}
public string PersonAddress {get;set;}
}
和地方的code定义集合
And somewhere in the code defined collection
List<Person> pesonsList = new List<Person>();
我们需要有一个过滤器,需要过滤的收集和结果返回给最终用户。比方说,我们有过滤器类型对象的集合
We need to have a filter that need to filter the collection and return the result to the end user. Let's say we have a collection of Filter type objects
class Filter
{
public string FieldName {get;set;}
public string FilterString {get;set;}
}
和地方在code,我们有
And somewhere in the code we have
List<Filter> userFilters = new List<Filter>();
因此,我们需要通过在userFilters集合定义的过滤器来过滤personsList集合的内容。其中, Filter.FieldName ==PersonName的|| Filter.FieldName ==PersonAddress。我怎样才能做到这一点与LINQ在阴凉的方式?类似的解决方案,开关/箱,或 可能的话,我想,在personsList扩展方法,决定从FiledName的人寻找到的财产,是已知的。别的东西?一些棘手的:) 谢谢你。
So we need to filter the content of the personsList collection by filters defined in the userFilters collection. Where the Filter.FieldName == "PersonName" || Filter.FieldName == "PersonAddress". How can I do that with LINQ in a cool way ? The solutions like switch/case, or may be, I thought, extension method on personsList that determines from the FiledName the property of the Person to look into, are known. Something else ? Something tricky:) Thank you.
推荐答案
您可以建立一个lambda EX pression创建使用防爆pression 合适的predicate code>类。
You can build a lambda expression to create a proper predicate using the Expression
class.
public static Expression<Func<TInput, bool>> CreateFilterExpression<TInput>(
IEnumerable<Filter> 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<Func<TInput, bool>>(Expression.Constant(false));
else
return Expression.Lambda<Func<TInput, bool>>(lambdaBody, param);
}
通过这个辅助方法,你可以创建任何的IQueryable℃的扩展方法; T&GT;
类,所以这应该工作的每一个LINQ后端:
With this helper method, you can create an extension method on any IQueryable<T>
class, so this should work for every LINQ backend:
public static IQueryable<T> Where<T>(this IQueryable<T> source,
IEnumerable<Filter> filters)
{
return Queryable.Where(source, CreateFilterExpression<T>(filters));
}
...你可以称之为是这样的:
...which you can call like this:
var query = context.Persons.Where(userFilters);
如果你想支持的IEnumerable&LT; T&GT;
的集合,以及,你需要使用这种额外的扩展方式:
If you want to support IEnumerable<T>
collections as well, you'll need to use this extra extension method:
public static IEnumerable<T> Where<T>(this IEnumerable<T> source,
IEnumerable<Filter> filters)
{
return Enumerable.Where(source, CreateFilterExpression<T>(filters).Compile());
}
请注意,这仅适用于字符串属性。如果你想上的字段筛选,您需要更改防爆pression.Property
到防爆pression.Field
(或 MakeMemberAccess
),如果你需要支持其他类型不是字符串属性,你必须向<$ C $提供更多类型的信息C>防爆pression.Constant 的 CreateFilterEx pression
方法的一部分。
Note that this only works for string properties. If you want to filter on fields, you'll need to change Expression.Property
into Expression.Field
(or MakeMemberAccess
), and if you need to support other types than string properties, you'll have to provide more type information to the Expression.Constant
part of the CreateFilterExpression
method.
这篇关于过滤收集与LINQ的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!