Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Refactoring switch cases

0.00/5 (No votes)
2 Jul 2009 1  
How to refactor switch cases

I want to show you how to apply a simple refactoring trick to a common pattern, the "switch case" statement.

Please take a look at the following program (a console app):

class Program
    {
        private static string options = null;
        private static readonly Type sportsEnumType = typeof(SportNews.Sports);
        static void Main(string[] args)
        {
            SportNews news = new SportNews();
            while (true)
            {
                Console.WriteLine();
                DisplayOptions();
                string key = Console.ReadKey().KeyChar.ToString();
                Console.WriteLine();
                try
                {
                    SportNews.Sports sport = (SportNews.Sports)(Enum.Parse(
                        sportsEnumType, key));
                    news.DisplayNews(sport);
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                    Console.ReadLine();
                    return;
                } 
            }
        }
        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();
                    SportNews.Sports sport = (SportNews.Sports)(enumValue);
                    optionsBuilder.AppendFormat("To display the news for {0} press {1}\n",
                        sport, enumValue);
                }
                options = optionsBuilder.ToString();
            }
            Console.WriteLine(options);
        }
    }

    public class SportNews
    {
        public enum Sports
        {
            Soccer = 0,
            BasketBall = 1,
            Rugby = 2,
            VolleyBall = 3
        }
        public void DisplayNews(Sports sport)
        {
            switch (sport)
            {
                case Sports.Soccer:
                    DisplayNewsForSoccer();
                    break;
                case Sports.BasketBall:
                    DisplayNewsForBasketBall();
                    break;
                case Sports.Rugby:
                    DisplayNewsForRugby();
                    break;
                case Sports.VolleyBall:
                    DisplayNewsForVolleyBall();
                    break;
                default:
                    throw new NotImplementedException(string.Format(
                         "The method for the sport {0} is not implemented", sport));
            }
        }
 
        private void DisplayNewsForSoccer()
        {
            Console.WriteLine("Displaying News for Soccer");
            // Real implementation below
            // Do something
        }
        private void DisplayNewsForBasketBall()
        {
            Console.WriteLine("Displaying News for BasketBall");
            // Real implementation below
            // Do something
        }
 
        private void DisplayNewsForRugby()
        {
            Console.WriteLine("Displaying News for Rugby");
            // Real implementation below
            // Do something
        }
 
        private void DisplayNewsForVolleyBall()
        {
            Console.WriteLine("Displaying News for VolleyBall");
            // Real implementation below
            // Do something
        }
     }

What does this do? Well, simply ask the user to press a given key to execute a determined action.

The running program looks like this:

console_app_running

Very simple, isn't?

This is fine for the number of alternatives that we are going to handle, but, what about if you add more items (+10) to the enum, you would need to add more cases to the switch statement, and so on. This is a very error prone process and also a maintenance nightmare.

What to do then? Well, the solution is very simple, you would need to change the switch statement by a lookup table, a Dictionary object is a good candidate to do this.

SHOW ME THE CODE!!. Here it is:

First let's create our Dictionary instance in the SportNews class constructor:

private Dictionary<Sports, Action> lookupTable;
 public SportNews()
 {
     lookupTable = new Dictionary<Sports, Action>()
     {
         { Sports.Soccer, DisplayNewsForSoccer },
         { Sports.BasketBall, DisplayNewsForBasketBall },
         { Sports.Rugby, DisplayNewsForRugby },
         { Sports.VolleyBall, DisplayNewsForVolleyBall }
     };
 }

Now let's change the DisplayNews method to get rid of the switch statement, it will end up as:

public void DisplayNews(Sports sport)
{
    Action displayMethod;
    if (lookupTable.TryGetValue(sport, out displayMethod))
    {
        displayMethod.Invoke();
    }
    else
    {
        throw new NotImplementedException(string.Format(
           "The method for the sport {0} is not implemented", sport));
    }
}

Isn't this more simple and clean?

Obviously, this code could be refactored even more, but for the purpose of the article, I think it is fine.

The final working demo can be found here.

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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here