Filtering collection with LINQ

后端 未结 4 1264
醉话见心
醉话见心 2021-02-02 02:19

Let\'s say we have a collection of Person objects

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


        
4条回答
  •  感动是毒
    2021-02-02 02:59

    You can build a lambda expression to create a proper predicate using the Expression class.

    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);
    }
    

    With this helper method, you can create an extension method on any IQueryable class, so this should work for every LINQ backend:

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

    ...which you can call like this:

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

    If you want to support IEnumerable collections as well, you'll need to use this extra extension method:

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

    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.

提交回复
热议问题