过滤收集与LINQ [英] Filtering collection with LINQ

查看:187
本文介绍了过滤收集与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 类。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆