How C# Compiler Looks At Switch Case Statements

Every developer writes a switch case statement at least once in their life of programming but as he/she understands that the switch is no longer maintainable, they tend to look for patterns and do refactoring.

In this post, we'll see what's actually inside of a switch case statement.

Here is the snippet of the code
  1. public void M(string x) {  
  2.         switch(x)  f
  3.         {  
  4.             case "a":  
  5.                 Console.WriteLine("a value");  
  6.                 break;  
  7.             case "b":  
  8.                 Console.WriteLine("b value");  
  9.                 break;  
  10.             case "c":  
  11.                 Console.WriteLine("c value");  
  12.                 break;  
  13.         }  
  14.     }  
 and the IL for the above code
  1. .method public hidebysig   
  2.         instance void M (  
  3.             string x  
  4.         ) cil managed   
  5.     {  
  6.         // Method begins at RVA 0x2050  
  7.         // Code size 73 (0x49)  
  8.         .maxstack 2  
  9.   
  10.         IL_0000: ldarg.1  
  11.         IL_0001: ldstr "a"  
  12.         IL_0006: call bool [mscorlib]System.String::op_Equality(stringstring)  
  13.         IL_000b: brtrue.s IL_0028  
  14.   
  15.         IL_000d: ldarg.1  
  16.         IL_000e: ldstr "b"  
  17.         IL_0013: call bool [mscorlib]System.String::op_Equality(stringstring)  
  18.         IL_0018: brtrue.s IL_0033  
  19.   
  20.         IL_001a: ldarg.1  
  21.         IL_001b: ldstr "c"  
  22.         IL_0020: call bool [mscorlib]System.String::op_Equality(stringstring)  
  23.         IL_0025: brtrue.s IL_003e  
  24.   
  25.         IL_0027: ret  
  26.   
  27.         IL_0028: ldstr "a value"  
  28.         IL_002d: call void [mscorlib]System.Console::WriteLine(string)  
  29.         IL_0032: ret  
  30.   
  31.         IL_0033: ldstr "b value"  
  32.         IL_0038: call void [mscorlib]System.Console::WriteLine(string)  
  33.         IL_003d: ret  
  34.   
  35.         IL_003e: ldstr "c value"  
  36.         IL_0043: call void [mscorlib]System.Console::WriteLine(string)  
  37.         IL_0048: ret  
  38.     } // end of method C::M  

What's in the IL?

I'll walk through this IL, at Line 12 in the IL there's a string equality checking which checks for the case statement to match once it is matched at Line 18 a brtrue.s IL_0028(a branch to target if the value is non-zero) is issued, this will check the result of the above line (the equality comparison).


Let's consider our best case to match "a" so the control is now transferred to IL_0028. This is where our write line statement is. So, we'll print that out.

What does the IL look like?

So, to give a glimpse of that IL in C# it is like this.

  1. public void M(string x)  
  2. {  
  3.     if (!(x == "a"))  
  4.     {  
  5.         if (!(x == "b"))  
  6.         {  
  7.             if (x == "c")  
  8.             {  
  9.                 Console.WriteLine("c value");  
  10.             }  
  11.         }  
  12.         else  
  13.         {  
  14.             Console.WriteLine("b value");  
  15.         }  
  16.     }  
  17.     else  
  18.     {  
  19.         Console.WriteLine("a value");  
  20.     }  
  21. }  

You might be refactoring the above if statements for a cleaner switch case statement but you'd end up with the above code when the compiler transforms the switch.

Wrapping up

If you ever refactor an if-else chain to a simple switch case statement then it is not so good but it will be clean as the compiler generates the if-else chain for you instead of you ending up in a tangled between if-else chain.


One tip for those who refactor these if-else statements to switch is run code metrics tools to see if there is any improvement on the maintainability index. I'm sure there won't be if the code metric tool really sees this IL stuff.


But, the switch is also not a good thing to do if you think from the design perspective of the application. That is why people tend to introduce the polymorphism instead of switch design or use dictionary patterns.


Thanks for reading.