Saturday, November 16, 2013

Casing vs Dictionary in C#

So you need to decide on which route to take in your code according to a specific condition
maybe you need a pretty large converter.

You are facing several options, one, is to code a lot of ifs
option which will be unreadable, unmaintainable and very difficult to code.
The other two are switch case statement or let a dictionary invoke some action.

So what is the better option? Dictionary or casing?
what is a better performer, what is cleaner in the code?

So let's write some code to explore it!

I've opened a new Console application and added a class, named CaseWayNumbers

   public class CaseWayNumbers
    {
        public void Selector(int num)
        {
            switch (num)
            {
                case 1:
                    DoSomthing();
                    break;
                case 2:
                    DoSomthing();
                    break;
                case 3:
                    DoSomthing();
                    break;
                case 4:
                    DoSomthing();
                    break;
                case 5:
                    DoSomthing();
                    break;
                case 6:
                    DoSomthing();
                    break;
                case 7:
                    DoSomthing();
                    break;
                case 8:
                    DoSomthing();
                    break;
                case 9:
                    DoSomthing();
                    break;
                case 10:
                    DoSomthing();
                    break;
                case 11:
                    DoSomthing();
                    break;
                default:
                    DoSomthing();
                    break;
            }
        }

        private void DoSomthing()
        {
        }
    }

And a second class, DictionaryWayNumbers
    public class DictionaryWayNumbers
    {
        private readonly Dictionary<int, Action> _caseDictionary;

        public DictionaryWayNumbers()
        {
            _caseDictionary = new Dictionary<int, Action>();
            _caseDictionary.Add(1, () => { });
            _caseDictionary.Add(2, () => { });
            _caseDictionary.Add(3, () => { });
            _caseDictionary.Add(4, () => { });
            _caseDictionary.Add(5, () => { });
            _caseDictionary.Add(6, () => { });
            _caseDictionary.Add(7, () => { });
            _caseDictionary.Add(8, () => { });
            _caseDictionary.Add(9, () => { });
            _caseDictionary.Add(10, () => { });
            _caseDictionary.Add(11, () => { });
        }

        public void Selector(int num)
        {
            Action action ;
            _caseDictionary.TryGetValue(num, out action);
            if (action != null) action.Invoke();
        }
    }

And to test if there's any significance if it's number or strings,
I've added some two other classes,
to deal with the strings.

    public class CaseWay
    {
        public void Selector(string str)
        {
            switch (str)
            {
                case "abit":
                    DoSomthing();
                    break;
                case "bus":
                    DoSomthing();
                    break;
                case "car":
                    DoSomthing();
                    break;
                case "door":
                    DoSomthing();
                    break;
                case "eye":
                    DoSomthing();
                    break;
                case "fuel":
                    DoSomthing();
                    break;
                case "google":
                    DoSomthing();
                    break;
                case "heisenberg":
                    DoSomthing();
                    break;
                case "imply":
                    DoSomthing();
                    break;
                case "justify":
                    DoSomthing();
                    break;
                case "kiosk":
                    break;
                default:
                    DoSomthing();
                    break;
            }
        }
        private void DoSomthing()
        {
        }
    }

    public class DictionaryWay
    {
        private readonly Dictionary<string, Action> _caseDictionary;

        public DictionaryWay()
        {
            _caseDictionary = new Dictionary<string, Action>();
            _caseDictionary.Add("abit", () => { });
            _caseDictionary.Add("bus", () => { });
            _caseDictionary.Add("car",() => { });
            _caseDictionary.Add("door",() => { });
            _caseDictionary.Add("eye",() => { });
            _caseDictionary.Add("fuel", () => { });
            _caseDictionary.Add("google", () => { });
            _caseDictionary.Add("heisenberg", () => { });
            _caseDictionary.Add("imply", () => { });
            _caseDictionary.Add("justify", () => { });
            _caseDictionary.Add("kiosk", () => { });
        }

        public void Selector(string str)
        {
            Action action;
            _caseDictionary.TryGetValue(str, out action);
            if (action != null) action.Invoke();
        }
    }
      
And finally some program to run it all and see what is performing better.

   class Program
    {
        static void Main(string[] args)
        {
            var strArr = new[] { "abit", "bus", "car", "door", "eye", "fuel", "google", "heisenberg", "imply", "justify", "kiosk" };
            var numArr = new[] { 1,2,3,4,5,6,7,8,9,10,11};

            var caseWay = new CaseWay();
            var dictionaryWay = new DictionaryWay();
            var caseWayNumbers = new CaseWayNumbers();
            var dictionaryWayNumbers = new DictionaryWayNumbers();

            var sw = new Stopwatch();
            sw.Start();

            for (int i = 0; i < 1000000; i++)
                foreach (var s in strArr)
                    caseWay.Selector(s);
            sw.Stop();

            var sw2 = new Stopwatch();
            sw2.Start();

            for (int i = 0; i < 1000000; i++)
                foreach (var s in strArr)
                    dictionaryWay.Selector(s);
            sw2.Stop();

            var sw3 = new Stopwatch();
            sw3.Start();

            for (int i = 0; i < 1000000; i++)
                foreach (var num in numArr)
                    caseWayNumbers.Selector(num);

            sw3.Stop();

            var sw4 = new Stopwatch();
            sw4.Start();

            for (int i = 0; i < 1000000; i++)
                foreach (var num in numArr)
                    dictionaryWayNumbers.Selector(num);
            sw4.Stop();


            Console.WriteLine("Case with strings: {0}", sw.ElapsedMilliseconds);
            Console.WriteLine("dictionary with strings: {0}", sw2.ElapsedMilliseconds);
            Console.WriteLine("Case with numbers: {0}", sw3.ElapsedMilliseconds);
            Console.WriteLine("dictionary with numbers: {0}",sw4.ElapsedMilliseconds);

        }
    }


And here are the run results (run on release mode):




















Conclusion
as you can see, using the switch case statement is slightly better on strings but much better on numbers.
In my opinion, it's cleaner with dictionary, and it's a better way to go if performance is not an issue, or that function is not called frequently, it shrinks the code lines, and a little bit easier to maintain.