许多多对多过滤器

时间:2009-01-29 23:05:21

标签: c# c#-3.0 delegates predicate

今天我们遇到了一个非常简单的问题,亲爱的谓词使问题变得更加简单。我们有一种事件日志,并希望使用标准列表过滤它的客户端(Windows窗体)。我们开始实施过滤多个类别。

private List<Events> FilterEventsByCategory(List<Events> events,
                                        List<Category> categories) 
{
  return events.FindAll(ev => 
      categories.Exists(category => category.CategoryId==ev.CategoryId)); 
}

下一步是实现其他几个过滤器。你知道一个很好的方法来概括这些可能以某种方式不必为每个过滤器编写一个方法吗?或者至少是一种干净的方式来获得我们想要同时应用的动态过滤器列表。

客户端仍然在框架3.0上,所以没有LINQ。

更新 我很难决定我的解决方案应该归功于谁。马克有一些不错的想法,并且非常擅长解释它们。最可能的是,如果我只是更好地解释了我的问题,我会得到他的回答。最终,cmartin提供的通用Filter类让我走上了正轨。下面使用的Filter类可以在cmartins的答案和用户类中找到,你可以自己做梦。

var categoryFilter = new Filter<Event>(ev => categories.Exists(category => category.CategoryId == ev.CategoryId));
var userFilter = new Filter<Event>(ev => users.Exists(user => user.UserId == ev.UserId));

var filters = new List<Filter<Event>>();
filters.Add(categoryFilter);
filters.Add(userFilter);

var eventsFilteredByAny = events.FindAll(ev => filters.Any(filter => filter.IsSatisfied(ev)));
var eventsFilteredByAll = events.FindAll(ev => filters.All(filter => filter.IsSatisfied(ev)));

2 个答案:

答案 0 :(得分:2)

re“所以没有LINQ” - 你看过LINQBridge了吗?由于您使用的是C#3.0,这将是理想的......

我担心主要问题,我不完全明白你想做什么以及你想避免什么 - 你能澄清一下吗?但是,如果使用LINQBridge方法,则可以使用连续的.Where()调用来组合过滤器。

对这个问题的一种解释是你不需要很多过滤方法 - 所以也许可以将一个或多个其他谓词传入方法 - 基本上是Func<Event, Func<Category, bool>> - 或者纯粹的2.0术语,{ {1}}:

Converter<Event, Predicate<Category>>

然后使用(如上所述):

private static List<Events> FilterEvents(
    List<Events> events,
    List<Category> categories,
    Converter<Events, Predicate<Category>> func)
{
    return events.FindAll(evt =>
        categories.Exists(func(evt)));
}

答案 1 :(得分:1)

以下是我将从哪里开始的非常基本的样本。

internal class Program
{
    private static void Main()
    {
        var ms = new Category(1, "Microsoft");
        var sun = new Category(2, "Sun");

        var events = new List<Event>
                         {
                             new Event(ms, "msdn event"),
                             new Event(ms, "mix"),
                             new Event(sun, "java event")
                         };

        var microsoftFilter = new Filter<Event>(e => e.CategoryId == ms.CategoryId);

        var microsoftEvents = FilterEvents(events, microsoftFilter);

        Console.Out.WriteLine(microsoftEvents.Count);
    }

    public static List<Event> FilterEvents(List<Event> events, Filter<Event> filter)
    {
        return events.FindAll(e => filter.IsSatisfied(e));
    }
}

public class Filter<T> where T: class
{
    private readonly Predicate<T> criteria;

    public Filter(Predicate<T> criteria)
    {
        this.criteria = criteria;
    }

    public bool IsSatisfied(T obj)
    {
        return criteria(obj);
    }
}

public class Event
{
    public Event(Category category, string name)
    {
        CategoryId = category.CategoryId;
        Name = name;
    }

    public int CategoryId { get; set; }
    public string Name { get; set; }
}

public class Category
{
    public Category(int categoryId, string name)
    {
        CategoryId = categoryId;
        Name = name;
    }

    public string Name { get; set; }
    public int CategoryId { get; set; }
}