Get rid of switch/case/if

Do you ever feel like (well, you should) these huge switch + case statements or too many ifs seem to be wrong? What if I told you, there’s one simple trick that will change your life, by getting rid of them? Ok, seriously – I have nothing against switch or if as the way of controlling the flow (I use them quite often) however, there are certain occasions at which the things could be done better. And let me show you another way to achieve the same goal which is much cleaner in terms of code readability and maintenance.


 

This post is all about coding, so let’s include some code in here. Here comes our “problem”:

This guy above surely may possess many more types, it could be also a magic string or anything else that makes sense (sorry, magic strings actually make no sense).
Anyway, you get the idea – there’s a variable, and based on its value that has to be checked first, we need to perform some action. BTW, before you start judging me – I’m aware that I don’t need to assign numerical values to the enums, but I like to be explicit about what I’m doing with my code, so I tend to follow this practice.

Back to the point, there’s a function that returns the type of operation that has to be dealt with:

First solution – switch + case:

Could be simplified a little bit if we could just use return statement and get rid of break keyword, yet still, it doesn’t make much difference for many available options.

Second solution – what if:

Same problem for too many options, could be simplified as well if the return value was used, but in the end, it doesn’t matter that much.

Third and final solution – dictionary of mappings between operation and function:

What did I do? Well, I’ve just created very simple mappings between the available operations and functions. These mappings can be much more sophisticated ones e.g. you may use Func in order to provide some input parameters or return a value.

And what happens now, if we want to perform an operation? This single line of code:

Quite easy, isn’t it? And you can even split your mappings declarations within dictionary into separate functions if there’s too many of them. The general idea, though, is that instead of using old fashioned switch/if statements for controlling the flow (that might grow tremendously) you just say: “Hey, let me point this operation to this function, and just invoke it if there’s a match” and create a dictionary or any other suitable collection to achieve the goal.

I do realize that the presented solution ain’t nothing fresh or new and it’s been there for years, yet there’s still so much code written using this old C style, so I hope that at least some of you will find this to be useful.

26 Comments Get rid of switch/case/if

  1. Pingback: Get rid of switch/case/if - How to Code .NET

    1. Piotr Gankiewicz

      Good point, the question is does it really make a difference in terms of performance here? 🙂
      Still, the point is that you can use as a key any type that you prefer, yet enum happens to be one of the most common examples.

      Reply
  2. m

    Yea the main benefit for me in this approach is that you separate two things – calling and selecting functions which make code much more testable

    Reply
  3. pwasiewicz

    I don’t like “Operations[operation]();” syntax – I know it is valid etc.. but just looks… strange 🙂 Just like compiling lambda expression and invoking returned delegate: “myLambdaExpr.Compile()()”. .

    Reply
  4. Pascal Bourguignon

    Congratulations! You’ve invented method dispatching. A little effort more, and you’ll invent object oriented programming, by storing those method dispatching tables in structures, and by passing a pointer to those structures to each of those functions…

    Reply
      1. vittore

        if you have more than one methpd like that, you can create hierarchy of classes and have factory method that will based on enum create Object of particular class. This way you will only have one instance of switch-case in your code, and all methods in your class heirarchy going to be virtual and easily accessible via base class typed variable.

        There are generally two approaches. Functional one tend to have dummy data structures with no methods defined on them and set of methods for your data structure each of the generally having pattern matching construct at top level.
        Object oriented approach is to have factory, that will be your only switch statement.

        Reply
        1. Piotr Gankiewicz

          Good idea with the factory, ultimately that’s what one should try to achieve – abstract away as much repeatable code as possible. Thanks for the well explained solution.

          Reply
  5. Nayan Shah

    The beauty here lies in it’s functional & declarative programming roots, i.e. treating code as data.

    Extracting the association between an operation and it’s action makes it easier to represent this data in any form. You could have dictionaries, read a json file, use attributes, etc.

    Reply
  6. Matthew Dippel

    If you’re concerned about boxing related to the use of an enum keyed dictionary, I wrote a library that handles this issue (and a lot of other enum corner cases) called DiagonacticEnumsExtensions on GitHub provides an IEqualityComprarer that eliminates the problem (it uses the underlying value with an unsafe cast operation — the whole thing is written in C++/CLI because C# doesn’t allow enum constraints — it’s compiled AnyCPU and covered to death in tests). That handles the slowdown if that kind of micro-opimisation is needed.

    This post inspired me to add a helper class that allows assigning delegates to enum values. I’ll probably have that added this week. Not sure why I didn’t think of that earlier, I do something similar rather regularly.

    Reply
    1. Piotr Gankiewicz

      Matthew, it’s very nice to hear that I’ve somehow inspired you do extend your library :). Personally, I’m not concerned that much with the boxing issue, but I’m pretty sure that other people will find it useful, good job!

      Reply
      1. Matthew Dippel

        Thanks! I wrote the implementation an hour ago and it’s passing tests. I’m going to sleep on it because I always think of something I’ve missed after a good rest so I’ll probably have it released tomorrow evening.

        I should have also been more clear in my previous comment, it’s a NuGet package “DiagonacticEnumExtensions” and the page links to its GitHub page.

        Reply
  7. marcin

    Nice article, but for me every presented approach have serious flaw. You can use if/switch/dictionary but if you *add* another constant to enumeration and forget to update your if/switch/dictionary you will not get compile time error. OK unit testing can catch errors like this but still we may expect something better from C#…

    This problem can be solved be declaring base class that will represent enum and subclasses that will represent enum constants and by moving code invoked for each constant into subclasses methods (there will be also abstract methods in base class). This will give us compile time errors, but of course it is not always applicable (e.g. in factory methods). BTW enums are implemented just like that in Java.

    Reply
    1. Piotr Gankiewicz

      You’re correct, but the whole point of this article was not to get rid of enum or any other type and replace it with a nice class. It’s all about dealing with enum or magic string when you can’t do much about that fact (e.g. replacing enum with a custom class).

      Reply

Leave a Reply to pwasiewicz Cancel reply

Your email address will not be published. Required fields are marked *