【问题标题】:Many many-to-many filters多对多过滤器
【发布时间】:2009-01-29 23:05:21
【问题描述】:

今天我们遇到了一个非常简单的问题,而亲爱的谓词使这个问题变得更加简单。我们有一种事件日志,并希望使用标准列表过滤它的客户端(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 类让我走上了正轨。下面使用的 Filter 类可以在 cmartins 的答案中找到,而 User 类是您自己梦想的。

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)));

【问题讨论】:

    标签: c# c#-3.0 delegates predicate


    【解决方案1】:

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

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

    对这个问题的一种解释是,您不想要很多过滤器方法 - 所以也许将一个或多个进一步的谓词传递到方法中 - 基本上作为 Func&lt;Event, Func&lt;Category, bool&gt;&gt; - 或者在纯 2.0 术语中,Converter&lt;Event, Predicate&lt;Category&gt;&gt;

    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);
    

    【讨论】:

    • 谢谢,我会看看 LINQBridge。我想为用户提供过滤多个标准列表的选项。如果我以某种方式使当前未使用的过滤器始终返回 true,则连续的 .Where() 调用可能会起作用。我明天去看看。
    • @jonelf:只是不要用你不想使用的过滤器调用 Where。
    • @Skeet:我如何使这些 Where 调用动态/用户选择?
    【解决方案2】:

    这是我将从哪里开始的一个非常基本的示例。

    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; }
    }
    

    【讨论】:

    • 乍一看,我没有看到除了我的问题中的方法之外,它是如何做到的,但它确实做到了。谢谢。
    猜你喜欢
    • 2011-01-14
    • 2016-01-22
    • 2014-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 2021-04-24
    相关资源
    最近更新 更多