首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用LINQ过滤集合

使用LINQ过滤集合
EN

Stack Overflow用户
提问于 2009-08-24 21:03:04
回答 4查看 15.5K关注 0票数 10

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

代码语言:javascript
复制
class Person 
{
     public string PersonName {get;set;}
     public string PersonAddress {get;set;}    
}

以及代码定义集合中的某个位置

代码语言:javascript
复制
List<Person> pesonsList = new List<Person>();

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

代码语言:javascript
复制
class Filter 
{
    public string FieldName {get;set;}
    public string FilterString {get;set;}
}

在我们的代码中

代码语言:javascript
复制
List<Filter> userFilters = new List<Filter>(); 

因此,我们需要通过在personsList集合中定义的过滤器过滤userFilters集合的内容。其中的Filter.FieldName == "PersonName“\x Filter.FieldName == "PersonAddress"。我怎么能用LINQ以一种很酷的方式做到这一点呢?解决方案,如开关/案例,或可能是,我认为,在personsList上的扩展方法,从FiledName确定的人的性质调查,是已知的。还有别的吗?一些棘手的问题:)谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-08-24 21:33:21

您可以构建一个lambda表达式来使用Expression类创建一个正确的谓词。

代码语言:javascript
复制
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>类上创建一个扩展方法,因此对于每个LINQ后端都可以这样做:

代码语言:javascript
复制
public static IQueryable<T> Where<T>(this IQueryable<T> source, 
                                          IEnumerable<Filter> filters)
{
    return Queryable.Where(source, CreateFilterExpression<T>(filters));
}

您可以这样调用...which:

代码语言:javascript
复制
var query = context.Persons.Where(userFilters);

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

代码语言:javascript
复制
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, 
                                           IEnumerable<Filter> filters)
{
    return Enumerable.Where(source, CreateFilterExpression<T>(filters).Compile());
}

请注意,这只适用于字符串属性。如果要对字段进行筛选,则需要将Expression.Property更改为Expression.Field (或MakeMemberAccess),如果需要支持字符串属性以外的其他类型,则必须向CreateFilterExpression方法的Expression.Constant部分提供更多的类型信息。

票数 10
EN

Stack Overflow用户

发布于 2009-08-24 21:17:51

你可以通过反射完成:

代码语言:javascript
复制
IQueryable<Person> filteredPersons = personsList.AsQueryable();
Type personType = typeof(Person);
foreach(Filter filter in userFilters) {
    filteredPersons = filteredPersons.Where(p => (string)personType.InvokeMember(filter.FieldName, BindingFlags.GetProperty, null, p, null) == filter.FilterString);
}

(未编译,但应沿着正确的轨道进行)

票数 3
EN

Stack Overflow用户

发布于 2009-08-24 21:40:40

你就不能就这么做

代码语言:javascript
复制
personList.Where(x => x.PersonName == "YourNameHere").ToList() ?
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1324774

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档