4

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!

5
  • Why not create a dictionary, where the key is your filter name, and the value is your filter object? Commented Apr 30, 2014 at 17:54
  • @NathanA that certainly is better than a switch statement. But in a perfect world, I would love to be able to add filter strings and filter objects and not have to worry about hard-coding them into a dictionary somewhere in the app. Commented Apr 30, 2014 at 17:56
  • 5
    Don't hard code them. For your filter objects, create a custom attribute that gives them 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. Commented Apr 30, 2014 at 17:59
  • @NathanA +1, can not give you more at this point. Dictionary very useful in scenario like this one. Commented Apr 30, 2014 at 18:02
  • @NathanA thanks, that does make great sense. If you're willing to write it up in answer form I'd love to give you the credit for it! Commented Apr 30, 2014 at 18:03

2 Answers 2

2

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));
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.