我可以使用Func / Predicate或Linq表达式来创建List <t>?</t>的通用过滤

时间:2011-08-24 00:39:56

标签: c# .net linq

使用以下课堂模型

public class Client
{
public string Name;
public List<Projects> Projects;
}

public class Projects
{
public string Value;
}

我想创建一些方法:GetHighGoldCustomers(); GetHighSilverCustomers(); GetHighBronzeCustomers() ....等

我们有大约15种不同的评级。

客户的评级取决于项目的价值,因此对于GetHighGoldCustomers(),我希望得到所有客户和那些有价值&gt;的项目。 200

进一步解释: 我想要List&lt; Client>。每个客户端都有List <Project>,这些项目将成为客户项目的子集。

我是否可以通过创建一个通用方法来实现这一点,在该方法中我将Expression作为参数传递,然后返回过滤掉的List<Client> and related List<Project>

谢谢

3 个答案:

答案 0 :(得分:1)

是的,您可以将表达式作为参数传递..就像这个↓

    public static IEnumerable<T> GetResultByCondtion<T>(
        IQueryable<T> src, 
        Expression<Func<T, bool>> predicate)
    {
        return src.Where(predicate);
    }

用法:

        var result = GetResultByCondtion<Client>(Clients.AsQueryable() , 
            c=>c.Projects.Sum(p=>p.Value) > 20);

        Console.WriteLine(result.Count());
        Console.ReadKey();

答案 1 :(得分:0)

你的意思是这样的吗?

private List<Client> ClientsWithValueGreaterThan(int value)
{
    return Clients.Where(c => c.Projects.Sum(p => p.Value) > value)
}

然后,基于此,您可以创建您描述的方法:

public GetHighGoldCustomers()
{
    return ClientsWithValueGreaterThan(200);
}

public GetHighSilverCustomers()
{
    return ClientsWithValueGreaterThan(100);
}

答案 2 :(得分:0)

我会考虑创建一组扩展方法来解决您的问题。像这样:

public static class ClientEx
{
    public static List<Client> GetCustomersByProjects(
        this IEnumerable<Client> clients,
        Func<IEnumerable<Projects>, IEnumerable<Projects>> selector)
    {
        var query =
            from c in clients
            let ps = selector(c.Projects).ToList()
            where ps.Any()
            select new Client()
            {
                Name = c.Name,
                Projects = ps,
            };

        return query.ToList();
    }

    public static List<Client> GetCustomersByProjectValuesGreaterThan(
        this IEnumerable<Client> clients, int value)
    {
        return clients.GetCustomersByProjects(ps => ps.Where(p => p.Value > value));
    }

    public static List<Client> GetHighGoldCustomers(
        this IEnumerable<Client> clients)
    {
        return clients.GetCustomersByProjectValuesGreaterThan(200);
    }
}

然后你可以在任何IEnumerable<Client>上使用这些方法,如下所示:

var customers = new List<Client>();
// load customers       
var highGold = customers.GetHighGoldCustomers();
var moreThan100 = customers.GetCustomersByProjectValuesGreaterThan(100);

现在,如果我能够坚持下去,我建议您创建一种方法,通过您在问题中提到的15个评级中的任何一个来回报客户。

首先,创建一个枚举来表示评级:

public enum ClientRating
{
    HighGold,
    HighSilver,
    HighBronze,
    Gold,
    Silver,
    Bronze,
    LowGold,
    LowSilver,
    LowBronze,
    // etc
}

然后,将以下代码添加到扩展类:

private static Dictionary<
        ClientRating, Func<IEnumerable<Projects>, IEnumerable<Projects>>>
    _ratingSelectors = new Dictionary<
        ClientRating, Func<IEnumerable<Projects>, IEnumerable<Projects>>>()
    {
        { ClientRating.HighGold, ps => ps.Where(p => p.Value > 200) },
        { ClientRating.HighSilver, ps => ps.Where(p => p.Value > 125) },
        { ClientRating.HighBronze, ps => ps.Where(p => p.Value > 60) },
        { ClientRating.Gold, ps => ps.Where(p => p.Value > 175) },
        { ClientRating.Silver, ps => ps.Where(p => p.Value > 100) },
        { ClientRating.Bronze, ps => ps.Where(p => p.Value > 40) },
        { ClientRating.LowGold, ps => ps.Where(p => p.Value > 150) },
        { ClientRating.LowSilver, ps => ps.Where(p => p.Value > 80) },
        { ClientRating.LowBronze, ps => ps.Where(p => p.Value > 20) },
    };

public static List<Client> GetCustomersByRating(
    this IEnumerable<Client> clients,
    ClientRating rating)
{
    return clients.GetCustomersByProjects(_ratingSelectors[rating]).ToList();
}

然后您就可以像这样查询您的客户:

var highGolds = customers.GetCustomersByRating(ClientRating.HighGold);
var silvers = customers.GetCustomersByRating(ClientRating.Silver);
var lowBronzes = customers.GetCustomersByRating(ClientRating.LowBronze);

这段代码的好处在于,评级的定义都保存在代码中的一个位置,如果您需要在不重新编译的情况下更改评级系统,也可以在运行时对字典进行修改。 / p>

如果评级系统依赖于selector上的属性而不仅仅是项目列表,并且如果您需要,例如,过滤器,我怀疑您需要更改Client表达式返回HighGold时退出HighSilver个客户。

这有帮助吗?