使用LINQ过滤集合 - c#

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

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

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

List<Person> pesonsList = new List<Person>();

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

class Filter 
{
    public string FieldName {get;set;}
    public string FilterString {get;set;}
}

在代码的某个地方

List<Filter> userFilters = new List<Filter>(); 

因此,我们需要通过userFilters集合中定义的过滤器来过滤personList集合的内容。其中Filter.FieldName ==“ PersonName” || Filter.FieldName ==“ PersonAddress”。我如何以一种很酷的方式使用LINQ来做到这一点?诸如开关/外壳之类的解决方案,或者
我认为,可能是对PersonList的扩展方法,该方法根据FiledName确定要研究的Person的属性。还有别的吗?棘手的事情:)
谢谢。

参考方案

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

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后端:

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

...您可以这样称呼:

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

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

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),并且如果需要支持字符串类型以外的其他类型,则必须提供更多类型信息以Expression.Constant方法的CreateFilterExpression部分。

将谓词<T>转换为Func <T,bool> - c#

我有一个包含成员Predicate的类,希望在Linq表达式中使用该类:using System.Linq; class MyClass { public bool DoAllHaveSomeProperty() { return m_instrumentList.All(m_filterExpression); } private IEnumerable&…

客户端反序列化为数组序列化字典<string,string>数据 - c#

我有一个字典,该字典使用C#中的JavaScriptSerializer进行了序列化。在客户端,我有:"{"dd049eda-e289-4ca2-8841-4908f94d5b65":"2","ab969ac2-320e-42e1-b759-038eb7f57178":"5�…

根据激活的Maven配置文件更新战争名称 - java

在pom中,我有两个配置文件。测试1测试2现在,我希望根据激活的配置文件更改战争名称。预期结果激活test1配置文件后,战争名称应为prefix-test1.war。激活test1和test2时,战争名称应为prefix-test1-test2.war。如果没有激活任何配置文件,则战争名称应为prefix.war。我的POM文件....<?xml ve…

合并List <T>和List <Optional <T >> - java

鉴于: List<Integer> integers = new ArrayList<>(Arrays.asList( 10, 12 )); List<Optional<Integer>> optionalIntegers = Arrays.asList( Optional.of(5), Optional.em…

将对象转换为List <object> - c#

我看过类似的问题,但没有什么合适的。我有一个碰巧包含列表的对象。我想把它变成我可以列举的东西。例如:object listObject; // contains a List<Something> List<object> list; list = listObject as List<object>; // list c…