Вопрос

Сегодня мы столкнулись с довольно простой проблемой, которая была еще проще благодаря предикатам dear.У нас было что-то вроде журнала событий, и мы хотели отфильтровать его на стороне клиента (Windows Forms), используя список критериев.Мы начали с реализации фильтрации по нескольким категориям.

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

Следующим шагом будет внедрение пары других фильтров.Знаете ли вы хороший способ обобщить их, чтобы, возможно, каким-то образом не приходилось писать по одному методу для каждого фильтра?Или, по крайней мере, чистый способ иметь динамический список фильтров, которые мы хотим применять одновременно.

Клиенты все еще работают на платформе framework 3.0, поэтому LINQ отсутствует.

Обновить: Мне было трудно решить, кому я должен отдать должное за свое решение.У Марка было несколько замечательных идей, и он действительно хорош в их объяснении.Скорее всего, я бы получил от него свой ответ, если бы только объяснил свою проблему немного лучше.В конечном счете, именно универсальный класс фильтра, предоставленный cmartin, навел меня на верный путь.Класс фильтра, используемый ниже, можно найти в ответе 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)));
Это было полезно?

Решение

Вот очень элементарный пример того, с чего бы я начал.

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

Другие советы

re "итак, нет LINQ" - вы смотрели на LINQBridge - Линкбридж?Поскольку вы используете C # 3.0, это было бы идеально...

Боюсь, что касается главного вопроса, я не до конца понимаю, что вы пытаетесь сделать и чего пытаетесь избежать - можете ли вы вообще уточнить?Но если вы используете подход LINQBridge, вы можете комбинировать фильтры, используя последовательные .Where() звонки.

Одна из интерпретаций вопроса заключается в том, что вам не нужно множество методов фильтрации - поэтому, возможно, передайте в метод один или несколько дополнительных предикатов - по существу, как 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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top