Question

This is killing me because I feel like I've seen something around before, but my searches are coming up empty and I don't have various patterns committed to memory (yet).

The Situation

I have a search grid that allows users to filter based on multiple attributes. The filters that users would like are passed in via a NameValueCollection and parsed out.

Currently, our legacy app checks for each potential filter in a separate if statement and then runs custom code. And since cyclomatic complexity just isn't my thing, 30 almost identical if statements bug me.

Towards a Better Way

Rather than continuing to check each item in a hard-coded way, I've re-written the parser so that now I can quickly obtain a list of all filters that will be applied. I'm also refactoring the filters themselves into their own classes.

So, I have a list of filters in string form ("Name", "BirthDate", etc.) and a bunch of classes (NameFilter, BirthDateFilter, etc.)

The Question

What is a good, standard way to take a list of strings representing filter names and turn it into a list of those filter objects themselves?

I suppose I could do some sort of FilterLocator with a LocateFilter(string filterName) method, but that seems like it would lead to one long switch statement and seems kind of blech.

I get the sense this is heading towards some sort of IoC/DI solution, but that I don't know enough about either to fully realize it yet.

Thanks for your thoughts!

Was it helpful?

Solution

Use a dictionary where the key is your filter name, and the value is your filter object.

Rather than hard coding this dictionary, create a custom attribute that gives each filter object a filter name. Then, use reflection to find those objects and create a static dictionary that can be used later. This way, there is no hard coding of the individual filter mappings at all.

Here's a sample set up for this:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class FilterNameAttribute : Attribute
{
    public FilterNameAttribute(string filterName)
    {
        FilterName = filterName;
    }

    public string FilterName { get; private set; }
}

[FilterName("MyFilterName")]
public class MyFilter
{
    //Do whatever you want here
}

public static class FilterHelper
{
    static Dictionary<string, Type> _filterTypesDict;

    static FilterHelper()
    {
        var assembly = Assembly.GetExecutingAssembly();

        _filterTypesDict = assembly.GetTypes()
            .Select(type => new { type, attrib = (FilterNameAttribute)type.GetCustomAttributes(typeof(FilterNameAttribute), false).FirstOrDefault() })
            .Where(x => x.attrib != null)
            .ToDictionary(x => x.attrib.FilterName, x => x.type);
    }

    public static Type GetFilterType(string filterName)
    {
        Type filterType;

        if (!_filterTypesDict.TryGetValue(filterName, out filterType))
        {
            throw new Exception("Unknown Filter Name.");
        }

        return filterType;
    }

    public static object GetFilter(string filterName)
    {
        return Activator.CreateInstance(GetFilterType(filterName));
    }
}

OTHER TIPS

Like in the comments I would definitely create a dictionary for your filters. Also with that I would create a base class for each filter with Name property and Apply method. And when your application starts up you can gather filter classes with reflection by the base filter class and populate the dictionary of filters using Name property as the key (or you can just use the name of the filter class), this way you don't even need to build up the dictionary manually, every time you add a filter class it will automatically appear int the dictionary. This will allow your LocateFilter(string filterName) method be really simple and straightforward.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top