使用LINQ过滤集合

Tig*_*ran 10 .net c# linq

假设我们有一个Person对象的集合

class Person 
{
     public string PersonName {get;set;}
     public string PersonAddress {get;set;}    
}
Run Code Online (Sandbox Code Playgroud)

并在代码定义集合中的某处

List<Person> pesonsList = new List<Person>();
Run Code Online (Sandbox Code Playgroud)

我们需要一个过滤器,需要过滤集合并将结果返回给最终用户.假设我们有一个Filter类型对象的集合

class Filter 
{
    public string FieldName {get;set;}
    public string FilterString {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

在我们的代码中的某个地方

List<Filter> userFilters = new List<Filter>(); 
Run Code Online (Sandbox Code Playgroud)

因此,我们需要通过userFilters集合中定义的过滤器来过滤personsList集合的内容.凡Filter.FieldName == "PERSONNAME" || Filter.FieldName =="PersonAddress".我怎样才能以酷炫的方式使用LINQ呢?像switch这样的解决方案,或者我认为,personList上的扩展方法可以从FiledName确定要查看的Person的属性.别的什么?有点棘手:)谢谢.

Rub*_*ben 10

您可以构建lambda表达式以使用Expression该类创建正确的谓词.

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);
}
Run Code Online (Sandbox Code Playgroud)

使用此辅助方法,您可以在任何IQueryable<T>类上创建扩展方法,因此这适用于每个LINQ后端:

public static IQueryable<T> Where<T>(this IQueryable<T> source, 
                                          IEnumerable<Filter> filters)
{
    return Queryable.Where(source, CreateFilterExpression<T>(filters));
}
Run Code Online (Sandbox Code Playgroud)

...你可以像这样打电话:

var query = context.Persons.Where(userFilters);
Run Code Online (Sandbox Code Playgroud)

如果您还想支持IEnumerable<T>集合,则需要使用此额外的扩展方法:

public static IEnumerable<T> Where<T>(this IEnumerable<T> source, 
                                           IEnumerable<Filter> filters)
{
    return Enumerable.Where(source, CreateFilterExpression<T>(filters).Compile());
}
Run Code Online (Sandbox Code Playgroud)

请注意,这仅适用于字符串属性.如果要对字段进行过滤,则需要更改Expression.PropertyExpression.Field(或MakeMemberAccess),如果需要支持除字符串属性之外的其他类型,则必须为方法的Expression.Constant某个部分提供更多类型信息CreateFilterExpression.