动态 Where 条件筛选 List<T>

6

我正在尝试为各种类创建动态过滤器。我们只能在运行时知道我们正在处理的类型。我需要ColumnName成为实际列(而不是字符串值)。

有没有一种简单的方法将字符串转换为列?

public static List<T> Filter<T>
    (this List<T> Source, string ColumnName, 
    string TypeOfCompare, string CompValue)
{
    IQueryable<T> matches = Source.AsQueryable();

    if (ColumnName.Length > 0)
    {
        matches = (IEnumerable)matches.Where(a => ColumnName == CompValue)
    }

    List<T> ReturnList2 = new List<T>();
    ReturnList2 = matches.ToList();
    return ReturnList2;
}
3个回答

13
基本上,您需要构建一个表达式树。幸运的是,使用Expression.Property并不难。您可以将其传递给Queryable.Where,也可以编译它并将其传递给Enumerable.Where。(显然,您还需要使用类似于Expression.Equal的东西,具体取决于您要进行的比较类型。) < p > CompValue是否表示实际值?TypeOfCompare表示什么?

我也不确定LINQ to Entities在这里扮演了什么角色...就我所看到的,您只是在使用LINQ to Objects。

编辑:好吧,这里有一个示例。它假定您想要相等性,但如果是这样,它会做您想要的事情。我不知道每次编译表达式树的性能影响如何-您可能需要为任何给定的名称/值组合缓存委托:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

static class Extensions
{
    public static List<T> Filter<T>
        (this List<T> source, string columnName, 
         string compValue)
    {
        ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
        Expression property = Expression.Property(parameter, columnName);
        Expression constant = Expression.Constant(compValue);
        Expression equality = Expression.Equal(property, constant);
        Expression<Func<T, bool>> predicate =
            Expression.Lambda<Func<T, bool>>(equality, parameter);

        Func<T, bool> compiled = predicate.Compile();
        return source.Where(compiled).ToList();
    }
}

class Test
{
    static void Main()
    {
        var people = new[] {
            new { FirstName = "John", LastName = "Smith" },
            new { FirstName = "John", LastName = "Noakes" },
            new { FirstName = "Linda", LastName = "Smith" },
            new { FirstName = "Richard", LastName = "Smith" },
            new { FirstName = "Richard", LastName = "Littlejohn" },
        }.ToList();

        foreach (var person in people.Filter("LastName", "Smith"))
        {
            Console.WriteLine(person);
        }
    }
}

没错,这是Linq to Objects...我们有包含数据的类,例如(名字,姓氏,电话),CompValue是我们要匹配的实际值...所以一个例子就是...personCollection = personCollection.Filter("LastName", "Smith");然后我们将返回“过滤”后的Smith集合...谢谢 - John K.
非常好,谢谢Jon。约翰K. - John K.
我认为如果你需要比较整数或字符串,将参数compValue的类型从“string”更改为“object”会更好。公共静态List <T>过滤器<T>(此列表<T>源,字符串columnName,对象compValue) - Delmonte
@Delmonte:我正在从问题中获取签名。我很可能会使其更加通用(添加类型参数),而不仅仅接受对象。 - Jon Skeet

0

你能否传递该列的选择器,而不是一个字符串ColumnName(我知道这并非总是可能的,但以防万一呢...)?如果可以的话,你就可以使用它。

顺便说一下,代码太复杂了。这个应该可以工作:

public static List<T> Filter<T>(
    this List<T> Source, Func<T, string> selector, string CompValue)
{
    return Source.Where(a => selector(a) == CompValue).ToList();
}

您可以按照以下方式调用代码:
var result = myList.Filter(x => x.ColumnName, "foo");

0

如果我的“matches”变量是动态运行时类型列表,会怎样? - Vishal Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接