1

今天我们遇到了一个非常简单的问题,而亲爱的谓词使这个问题变得更加简单。我们有一种事件日志,并希望使用标准列表过滤它的客户端(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。

更新: 我很难决定我的解决方案应该归功于谁。Marc 有一些不错的想法,并且非常擅长解释它们。如果我能更好地解释我的问题,我很可能会从他那里得到答案。最终,是 cmartin 提供的通用 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)));
4

2 回答 2

2

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

恐怕主要问题是,我不完全理解您要做什么以及要避免什么-您能澄清一下吗?但是,如果您使用 LINQBridge 方法,您可以使用连续.Where()调用来组合过滤器。

对这个问题的一种解释是,您不想要很多过滤器方法 - 所以也许将一个或多个进一步的谓词传递给该方法 - 基本上作为 a Func<Event, Func<Category, bool>>- 或纯 2.0 术语, a 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)));
}

然后将其用作(如上):

var result = FilterEvents(events, categories,
      evt => category => category.CategoryId==evt.CategoryId);
于 2009-01-29T23:13:27.803 回答
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; }
}
于 2009-01-29T23:25:19.217 回答