改进数据过滤代码的重用

时间:2012-01-26 22:47:41

标签: c# linq design-patterns

有人想帮助我成为更好的程序员吗?

我有一个应用程序,我按照各种标准过滤对象集合。现在我的代码工作,但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 个答案:

答案 0 :(得分:2)

您基本上是在重新实施Contains()方法 - 您可以这样做:

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

然后你的applyFilters方法如下所示:

public IEnumerable<ExampleData> applyFilters(SearchCriteria criteria, IEnumerable<ExampleData> data)
{
    data = data.Where(x=> criteria.FormTemplateSelected.Contains(x.SomeValue1)
                       && criteria.FormTemplateSelected.Contains(x.SomeValue2));
    return data;
}

答案 1 :(得分:1)

一般情况下,您可以使用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);

根据具体情况,您可以更进一步,在代表身上应用更复杂的逻辑,但很难从您粘贴的代码中判断出您最感兴趣的部分。