C# Switch Statement Limitations - Why

C# switch statement limitations - why?

This is my original post, which sparked some debate... because it is wrong:

The switch statement is not the same
thing as a big if-else statement.
Each case must be unique and evaluated
statically. The switch statement does
a constant time branch regardless of
how many cases you have. The if-else
statement evaluates each condition
until it finds one that is true.


In fact, the C# switch statement is not always a constant time branch.

In some cases the compiler will use a CIL switch statement which is indeed a constant time branch using a jump table. However, in sparse cases as pointed out by Ivan Hamilton the compiler may generate something else entirely.

This is actually quite easy to verify by writing various C# switch statements, some sparse, some dense, and looking at the resulting CIL with the ildasm.exe tool.

Why can a C# switch statement not accept the 'dynamic' type?

Because constants used in the case-labels must be compile time constants compatible with the governing type.

You won't be sure about the dynamic variable at the compile time.

How would you know that from which value you will compare in you case-label as dynamic variable can hold any type of value.

Look at this

dynamic thing = "thing";
//and some later time `thing` changed to
thing = 1;

Now think about your case-label (in which type of value you will compare)

Is the switch statement evaluation thread-safe?

You're actually posting two questions.

Is it threadsafe?

Well, obviously it is not, another thread might change the value of X while the first thread is going into the switch. Since there's no lock and the variable is not volatile you'll switch based on the wrong value.

Would you ever hit the default state of the switch?

Theoretically you might, as updating a 64 bits is not an atomic operation and thus you could theoretically jump in the middle of the assignment and get a mingled result for x as you point out. This statistically won't happen often but it WILL happen eventually.

But the switch itself is threadsafe, what's not threadsafe is read and writes over 64 bit variables (in a 32 bit OS).

Imagine instead of switch(x) you have the following code:

long myLocal = x;
switch(myLocal)
{
}

now the switch is made over a local variable, and thus, it's completely threadsafe. The problem, of course, is in the myLocal = x read and its conflict with other assignments.

Why does Visual Studio 2019 recommend a switch expression instead of a switch statement?

In the example you give there's not a lot in it really. However, switch expressions are useful for declaring and initializing variables in one step. For example:

var description = reason switch 
{
Reasons.Case1 => "string1",
Reasons.Case2 => "string2",
_ => throw new ArgumentException("Invalid argument")
};

Here we can declare and initialize description immediately. If we used a switch statement we'd have to say something like this:

string description = null;
switch(reason)
{
case Reasons.Case1: description = "string1";
break;
case Reasons.Case2: description = "string2";
break;
default: throw new ArgumentException("Invalid argument");
}

One downside of switch expressions at the moment (in VS2019 at least) is that you can't set a breakpoint on an individual condition, only the whole expression. However, with switch statements you can set a breakpoint on an individual case statement.

Why C# switch only runs the first statement?

Unable to reproduce. For example, run this:

using System;
using System.Windows.Forms;

class Program
{
static void Main(string[] args)
{
string foo = "FOO";
switch (foo)
{
case "FOO":
MessageBox.Show("Dog");
MessageBox.Show("Cat");
break;
}
}
}

Both message boxes show up. I suspect something else is going on that you're not showing us. If you can edit your question to include a short but complete program which does demonstrate the problem, that will be a different matter.

Is there any significant difference between using if/else and switch-case in C#?

SWITCH statement only produces same assembly as IFs in debug or compatibility mode. In release, it will be compiled into jump table (through MSIL 'switch' statement)- which is O(1).

C# (unlike many other languages) also allows to switch on string constants - and this works a bit differently. It's obviously not practical to build jump tables for strings of arbitrary lengths, so most often such switch will be compiled into stack of IFs.

But if number of conditions is big enough to cover overheads, C# compiler will create a HashTable object, populate it with string constants and make a lookup on that table followed by jump. Hashtable lookup is not strictly O(1) and has noticeable constant costs, but if number of case labels is large, it will be significantly faster than comparing to each string constant in IFs.

To sum it up, if number of conditions is more than 5 or so, prefer SWITCH over IF, otherwise use whatever looks better.

two styles of C# switch-return statements, what is the difference?

There is no practical difference. Both formats will behave the same as:

if(value==1)
return "a";
else if(value==2)
return "b";
else
return "c";

The first approach, of using default, is strongly recommended. It's the one that will follow style guidelines, and that will make the intent of the code clearest.



Related Topics



Leave a reply



Submit