Click here to Skip to main content
12,064,855 members (40,889 online)
Click here to Skip to main content
Add your own
alternative version


15 bookmarked

Refactoring Switch Statements (Take 2)

, 2 Jul 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
How to refactor Switch statements.

Hello to everyone, had been such a long time since my last article. Many interesting things had been going on in Sansir lately that had been taking my entire free time, and also I’m a man with strong family links, so that makes it difficult to publish articles frequently. I am not complaining about it, not at all, color me “happy”.

OK, stop whining.

In one of our previous articles, I showed you how to refactor a piece of code which was deciding what method to execute based on the evaluation result of a switch statement; you can read about it here.

As a final note, I stated in the article that the presented code could be refactored even further, because if you look carefully, we had just moved the maintenance nightmare to another place in the program, but the original problem still exists.

What to do then? This is what I would do:

  1. Create a specific class for each sport that is going to be handled; those classes must implement a simple interface and they need to be decorated with an attribute where is specified the target sport that it will handle. Like:
  2. public interface INewsDisplayer
        void Display();
    public class NewsDisplayerDefinitionAttribute : Attribute 
        public NewsDisplayerDefinitionAttribute(Sports sport) 
            Sport = sport; 
        public Sports Sport { get; private set; } 

    An implementation of this would look like:

    public class SoccerNewsDisplayer : INewsDisplayer 
    #region INewsDisplayer Members 
        public void Display() 
            Console.WriteLine("Displaying News for Soccer"); 
            // Real implementation below 
            // Do something 
  3. Using the Factory Pattern, create a class that takes a Sport parameter and returns an IEnumerable<INewsDisplayer> instance. One difference with our previous attempt is that we are going to be able to define more than one implementation for a given Sport. This factory class will scan all the assemblies for the current AppDomain, and if it finds a type which follows the pattern that I have described in the previous point, it will read the metadata and append an instance of this type to a dictionary that will serve us as our lookup table to return the correct instances for the requested Sport. This factory class looks like:
  4. public static class NewsDisplayerFactory 
        private static readonly IDictionary<Sports, IEnumerable<INewsDisplayer>> 
          lookupTable = new Dictionary<Sports, IEnumerable<INewsDisplayer>>(); 
        static NewsDisplayerFactory() 
        private static void BootStrap() 
            // Find all types in all the assemblies from the current appdomain 
            // that have a correct implementation of 
            // News Displayer (NewsDisplayerDefinitionAttribute + INewsDisplayer) 
            var interfaceFullName = typeof (INewsDisplayer).FullName; 
            var newsDisplayerAttributeType = typeof (NewsDisplayerDefinitionAttribute); 
            var result = from 
                assembly in AppDomain.CurrentDomain.GetAssemblies() 
                type in assembly.GetTypes() 
                definition = type 
                .GetCustomAttributes(newsDisplayerAttributeType, true) 
                type.GetInterface(interfaceFullName) != null && definition != null 
                (INewsDisplayer) Activator.CreateInstance(type) 
                by definition.Sport; 
            // Filling the dictionary 
            foreach (var item in result) 
                lookupTable.Add(item.Key, item.ToList()); 
        public static IEnumerable<INewsDisplayer> GetInstance(Sports sport) 
            IEnumerable<INewsDisplayer> newsDisplayer; 
            if (lookupTable.TryGetValue(sport, out newsDisplayer)) 
                return newsDisplayer; 
                throw new NotImplementedException(string.Format(
                  "The method for the sport {0} is not implemented", sport)); 
  5. Using the Strategy Pattern, we are going to change our SportNews class to change its context by passing to it the kind of Sport that it is going to handle. That will look like:
  6. public class SportNews 
        private IEnumerable<INewsDisplayer> newsDisplayer; 
        public void SetContext(Sports sport) 
            newsDisplayer = NewsDisplayerFactory.GetInstance(sport); 
        public void DisplayNews() 
            foreach (var displayer in newsDisplayer) 

    That’s it, with our new approach, we can continue adding NewsDisplayers and use those in our program without touching other parts of our program; doing it by adding more classes to our assembly or dropping assemblies into the bin directory (isn’t this called the plug-in model?).

Finally, I’ll like to show our Program class where every component is used to perform the original idea for this program:

class Program 
    private static string options = null; 
    private static readonly Type sportsEnumType = typeof(Sports); 
    static void Main(string[] args) 
        var news = new SportNews(); 
        while (true) 
            var key = Console.ReadKey().KeyChar.ToString(); 
                var sport = (Sports)(Enum.Parse(sportsEnumType, key)); 
            catch (Exception ex) 
    private static void DisplayOptions() 
        if (options == null) 
            StringBuilder optionsBuilder = new StringBuilder(); 
            FieldInfo[] enumFields = sportsEnumType.UnderlyingSystemType.GetFields(
                                     BindingFlags.Public | BindingFlags.Static); 
            foreach (FieldInfo enumField in enumFields) 
                object enumValue = enumField.GetRawConstantValue(); 
                Sports sport = (Sports)(enumValue); 
                optionsBuilder.AppendFormat("To display the news for {0} press {1}\n", 
                                            sport, enumValue); 
            options = optionsBuilder.ToString(); 

You can download the working sample from here.

Happy coding, see you soon.

Shameless plug: You can check this article on my blog here


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Web Developer
Peru Peru
No Biography provided

You may also be interested in...

Comments and Discussions

SuggestionGood but too terse, IMHO Pin
James Jensen3-Nov-14 6:26
professionalJames Jensen3-Nov-14 6:26 
GeneralMy vote of 5 Pin
Anonymous delegate28-Sep-10 7:44
memberAnonymous delegate28-Sep-10 7:44 
GeneralMy vote of 1 Pin
Pavel Vladov8-Jul-09 3:04
memberPavel Vladov8-Jul-09 3:04 
GeneralRe: My vote of 1 Pin
emiaj10-Jul-09 6:21
memberemiaj10-Jul-09 6:21 
Hi, I know it looks like overenginnering such a simple requirement (given a set of fixed possibilities, execute some code), perhaps the scenario that I present in the article is simplistic and that contributes to your opinion about it.

Pavel Vladov wrote:
extremely slow foreach loop

How slow?? 1ms slow? 10ms slow? 100ms slow? Thats such a relative concept that needs to be defined precisely .

Pavel Vladov wrote:
A simple advice from me: do not make the life more complicated, its complicated enough already

Don't get me wrong, I understand what you mean, and I absolutely agree with you, nobody shouldn't use this approach for simple programs like this one. But if you have some program that have an static list of cases (an enum) but it requires an extensible way to execute a set of actions for each possible option, then definitely this article would give you an idea of how this could be accomplished.

Also, I think there is some infrastructure code here (the thing about discovering implementations for each enum member) that could be delegate to a library which does this automatically for you (StructureMap or something alike), but I didn't wanted to introduce more concepts/concerns than the article already has.

Finally, thanks for your comments (no matter if you vote 1 or 5), I appreciate the time used just to read this article (life is short, you know Smile | :) ).

Best regards,

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.160204.4 | Last Updated 2 Jul 2009
Article Copyright 2009 by emiaj
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid