The switch
opcode in CIL is quite limited compared to what C# offers. It accepts a single jump table containing a sequence of labels to where to jump if the argument is equal to the index of the label. So, unlike C#, you can only switch on a non-negative integer, and only for all cases from 0 to n.
On the other hand, C# switch can be used on strings and even negative numbers.
I have done some tests, and for strings, it seems a simple ==
equality is employed, so despite a popular belief, switch
is not faster than if
/else if
in that case. ==
calls Equals
, which does ordinal comparison (i.e. bytewise).
Also if seems that if the cases are "sequential enough", it is compiled to a real switch
opcode. The compiler is even so clever it finds the minimum of the cases and subtracts it from the value, effectively making the cases start from 0.
If there are some cases outside the sequential range, it turns them to normal comparisons, but keeps the switch. If there are gaps in the switch, it makes them point to the next instruction (default:
).
So I wonder, what is the full set of rules the compiler considers when compiling the switch
statement in C#? When does it decide to turn it to the switch
opcode, and when is it transformed only to normal comparisons?
Edit: Looks like for large amount of strings in switch
, it caches them in a static Dictionary<string, int>
.