过滤收集与LINQLINQ

由网友(我的微笑只给懂的人看)分享简介:让我们说我们有Person对象的集合Let's say we have a collection of Person objects class Person {public string PersonName {get;set;}public string PersonAddress {get;set;}...

让我们说我们有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 类。

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 ),如果你需要支持其他类型不是字符串属性,你必须向防爆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.

阅读全文

相关推荐

最新文章