Улучшение повторного использования кода фильтрации данных - PullRequest
0 голосов
/ 27 января 2012

Кто-нибудь хочет помочь мне стать лучшим программистом?

У меня есть приложение, в котором я фильтрую коллекцию объектов по множеству критериев. Прямо сейчас мой код работает, но 90% дублируется, что, как мне кажется, означает, что я делаю что-то не так. Любые предложения о том, как сделать более многоразовым фильтрующий код?

Предположим, у меня есть коллекция таких объектов:

    public class ExampleData
{
    public int SomeValue1 { get; set; }
    public int SomeValue2 { get; set; }
    public int SomeValue3 { get; set; }
    public string SomeValue4 { get; set; }
}

А вот и мой класс фильтра. Посмотрите на комментарии к коду.

  class ExampleFilter
{
    public ExampleFilter()
    {
    }

    public IEnumerable<ExampleData> applyFilters(SearchCriteria criteria, IEnumerable<ExampleData> data)
    {
        //The body of these methods is almost identical...how can I better design this process so I don't cut and paste 90% of the code?
        data = filterByValue1Selections(criteria.FormTemplateSelected, data);
        data = filterByValue2Selections(criteria.FormTemplateSelected, data);
        return data;
    }

    public IEnumerable<ExampleData> filterByValue1Selections(List<int> value1Ids, IEnumerable<ExampleData> data)
    {
        if (value1Ids != null)
        {
            IEnumerable<ExampleData> dataQuery = null;
            foreach (int selectedValueIds in value1Ids)
            {
                //See http://justgeeks.blogspot.com/2011/01/using-linq-in-foreach-loop-to-build.html
                //For explanation of why we copy this locally
                int selectedId = selectedValueIds;
                if (dataQuery == null)
                {
                    //This code and the similar block in the else are the only differences in these methods
                    dataQuery = data.Where(t => t.SomeValue1 == selectedId);
                }
                else
                {
                    dataQuery = dataQuery.Union(data.Where(t => t.SomeValue1 == selectedId));
                }
            }
            data = dataQuery;
        }
        return data;
    }

    public IEnumerable<ExampleData> filterByValue2Selections(List<int> value2Ids, IEnumerable<ExampleData> data)
    {
        if (value2Ids != null)
        {
            IEnumerable<ExampleData> dataQuery = null;
            foreach (int selectedValueIds in value2Ids)
            {
                //See http://justgeeks.blogspot.com/2011/01/using-linq-in-foreach-loop-to-build.html
                //For explanation of why we copy this locally
                int selectedId = selectedValueIds;
                if (dataQuery == null)
                {
                    dataQuery = data.Where(t => t.SomeValue1 == selectedId);
                }
                else
                {
                    dataQuery = dataQuery.Union(data.Where(t => t.SomeValue1 == selectedId));
                }
            }
            data = dataQuery;
        }
        return data;
    }


}

Ответы [ 2 ]

2 голосов
/ 27 января 2012

Вы в основном повторно реализуете метод Contains() - вы можете просто сделать:

List<int> valueIds = ...;
var filteredData = data.Where(x=> valueIds.Contains(x.SomeValue1));

Тогда ваш метод applyFilters будет выглядеть так:

1 голос
/ 27 января 2012

В общем, вы можете использовать Func<T, TResult> delegates для обобщения повторяющихся FilterByValue методов, вы можете попробовать что-то вроде этого (псевдокод):

public IEnumerable<T> FilterByValue<T>(List<int> value1Ids, IEnumerable<T> data, Func<T, int> selector)
{
    if (value1Ids != null)
    {
        IEnumerable<ExampleData> dataQuery = null;
        foreach (int id in value1Ids)
        {
            int selectedId = id;
            if (dataQuery == null)
            {
                dataQuery = data.Where(x => selector(x) == id);
            }
            else
            {
                dataQuery = dataQuery.Union(data.Where(x => selector(x) == id));
            }
        }

        data = dataQuery;
    }

    return data;
}

Таким образом, вы можете передать фактический выбор свойства:

FilterByValue(criteria.FormTemplateSelected, data, x => SomeValue1);
FilterByValue(criteria.FormTemplateSelected, data, x => SomeValue2);

В зависимости от сценария вы можете пойти еще дальше и применить более сложную логику к делегату, но по коду, который вы вставили, трудно судить, какая часть вас интересует больше всего.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...