switch vs Select Case

M

ME

In C# the following code generates a compiler error
("A constant value is expected"):

public void Test(string value)
{
switch (value)
{
case SimpleEnum.One.ToString():
MessageBox.Show("Test 1");
break;
case SimpleEnum.Two.ToString():
MessageBox.Show("Test 2");
break;
case SimpleEnum.Three.ToString():
MessageBox.Show("Test 3");
break;
}
}

The Visual Basic.NET version does not:

Public Sub Test(ByVal value As String)
Select Case value
Case SimpleEnum.One.ToString()
MessageBox.Show("Test 1")
Case SimpleEnum.Two.ToString()
MessageBox.Show("Test 2")
Case SimpleEnum.Three.ToString()
MessageBox.Show("Test 3")
Case Else
End Select
End Sub


How can this be done in C# and also why is this true?
 
B

Bruce Wood

"case" expressions must be constants in C#. As soon as you use
"ToString" you are using a method result, which is variable by
definition.

Anyway, in both VB.NET and C# I wouldn't do it that way. To me, you
have it flipped around backward. You're better off converting the
string to the enumeration, and then doing the switch. The only extra
code is to catch errors:

public void Test(string value)
{
try
{
SimpleEnum enumVal = Enum.Parse(typeof(SimpleEnum), value,
false);
switch (enumVal)
{
case SimpleEnum.One: MessageBox.Show("Test 1"); break;
case SimpleEnum.Two: MessageBox.Show("Test 2"); break;
case SimpleEnum.Three: MessageBox.Show("Test 3"); break;
default:
MessageBox.Show(String.Format("Added new enum {0}
without modifying switch", enumValue);
break;
}
}
catch (ArgumentException)
{
MessageBox.Show(String.Format("String {0} is not a
SimpleEnum.", value);
}
}
 
B

Bob Grommes

Clearly VB.NET is not as strict about what can be tested. My suspicion
is that a C# switch, if you can live within its requirements, is faster,
although I doubt it matters in the real world very often.

A C# construct like the following will do what you want:

if (value == SimpleEnum.One.ToString()) {
MessageBox.Show("Test 1");
} else if (value == SimpleEnum.Two.ToString()) {
MessageBox.Show("Test 2");
} else if (value == SimpleEnum.Three.ToString()) {
MessageBox.Show("Test 3");
} else {
MessageBox.Show("Default Test");
}

--Bob
 
O

Octavio Hernandez

Hi,

The C# specs indicate that you should place constant expressions in case
clauses. Your calls to ToString() are not.
VB.NET Select Case is obviously more "dynamic" and calculates the expression
at runtime and then checks for equality. This scheme may look more dynamic,
but offers less opportunities for code optimization.
I think you should rewrite your method in order to receive not a string, but
a SimpleEnum parameter, which can be used later in the switch statement. It
will be safer and more efficient:

public void Test(SimpleEnum se)
{
switch (se)
{
case SimpleEnum.One:
MessageBox.Show("Test 1");
break;
case SimpleEnum.Two:
MessageBox.Show("Test 2");
break;
}
}

Regards - Octavio
 
B

Brooke

Not sure if this is what you are trying to do, but this works fine under 2.0
framework.

using System;

public class MyTestClass {

private enum Nums {
One = 1,
Two,
Three
}

public static void Test(string Value) {

switch(Value) {

case "One":
Console.WriteLine("Test One");
break;

case "Two":
Console.WriteLine("Test Two");
break;

case "Three":
Console.WriteLine("Test Three");
break;
}
}

public static int Main() {

Test(Enum.GetName(typeof(Nums), Nums.Two));
Test(Enum.GetName(typeof(Nums), Nums.One));
Test(Enum.GetName(typeof(Nums), Nums.Three));
Test(Enum.GetName(typeof(Nums), Nums.Two));

System.Console.Write("\nPress any key to continue...");
System.Console.ReadKey();

return 0;
}
}


Bye
 
W

Wiebe Tijsma

Hi Brooke,

Yes, it works the way you apply it, you use string constants, but you
can't use variables. In general practice, it's better to avoid 'magic'
string constants like these.

Bruce's way is preferable...

Wiebe
 
M

ME

I can see the enum example is throwing several off the point. Here is another EXAMPLE of a time when I would like to use a dynamic switch:

private void WorkWithSelectedColumn(TemplateADataSet.SiteOptionsRow row, string columnName)
{

//Switch 1 works:
switch (columnName)
{
case "Key":
break;
case "Value":
break;
case "UniqueID":
break;
}

//Switch 2 does not work in c# but the vb version will work
switch (columnName)
{
case row.Key:
break;
case row.Value:
break;
case row.UniqueID:
break;
}
}

I realize that C# requires a constant. My question is, why give the VB guys the "option" of creating a dynamic switch/select case but not give it to the C# guys? Typically the way I handle this particular example is by using SQL to generate some code constants (public constants of every column name of every table in my data base) and use those in place of the "xxx" in switch 1. It would be nice to be able to perform the task in switch 2, which would leave out a step (VS builds the dataset for me just fine).

Thanks,

Matt
 
B

Bruce Wood

I believe that the answer to the question, "Why doesn't C# allow
variables or expressions as 'case' values?" is as follows.

Languages that allow variable 'case' values, or that go even farther
and allow conditions case 'case' values, have little choice but to turn
switches with variable or conditional cases into a long sequence of if
/ then / else if / ... else statements. As such, VB.NET (for example)
is doing some magic behind the scenes to turn what looks like a switch
into something that isn't a switch at all, in order to allow the
programmer to use a more pleasing construct.

C# (and C and C++) take the attitude that what you code is what you
get. The language doesn't play monkey business behind the scenes. In
C#, a 'switch' is always a fast selection amongst alternatives. The
language might choose to generate a switch as a sequence of tests, but
only if it were faster to do it that way. In keeping with this
philosophy, the language doesn't allow you to write code that looks
like a fast selection amongst alternatives but in fact is not.
Therefore, 'case' values must be constants, so that the strategy for
deciding how to arrive at the correct case can be decided at compile
time.
 
J

Jon Skeet [C# MVP]

C# (and C and C++) take the attitude that what you code is what you
get. The language doesn't play monkey business behind the scenes. In
C#, a 'switch' is always a fast selection amongst alternatives. The
language might choose to generate a switch as a sequence of tests, but
only if it were faster to do it that way. In keeping with this
philosophy, the language doesn't allow you to write code that looks
like a fast selection amongst alternatives but in fact is not.
Therefore, 'case' values must be constants, so that the strategy for
deciding how to arrive at the correct case can be decided at compile
time.

Ironically, C# *does* play monkey business behind the scenes when it
comes to strings, as noted elsewhere (using a Hashtable when there are
more than a few strings). Fortunately, it's still a fast selection, but
perhaps not quite as fast as might be expected.
 
M

ME

Bruce,

I agree with your logic. So the next question I would have is why does VB
still allow it? Shouldn't the languages be close here? The diffence
between a dynamic construct(vb) and a static one could cause some major
grief if re-wrote from VB to C#. It could be said that this WOULD make C# a
better language. Isn't that what MS is trying to squash?

Thanks,

Matt
 
S

Steven Nagy

This is even better:

select case true
case 3 < 7

case 4 > 7
end select

I wish you could do this in C# .... (I can't remember why I wish this,
something to do with large selection statements)
 
M

ME

Though I agree with Bruce as to why, I also must state that sometimes
performance is not the biggest issue. In some cases where scalability is
not an issue this feature (a dynamic switch) would be handy.

thanks,

matt
 
B

Bruce Wood

All true, but I think it comes down to the philosophy of the language.
VB has always been a language that "does a lot for you". For example,
in VB this sort of thing would be perfectly legal (I'm using C# syntax
to illustrate):

int val = 15;
string valString = val;

whereas C# forces you to make an explicit call:

int val = 15;
string valString = val.ToString();

The same with the switch: VB does a lot more for you behind the scenes,
but the downside is that it's not always obvious when you've asked the
language to do something inefficient.

The C# philosophy has always been "leaner and meaner" than that of VB.
C# forces you to be more explicit. The language doesn't make as many
assumptions as to what you might want or what you might mean.

So far as I know, there is no other reason why the language wouldn't
allow you to specify variable 'case' values, or even conditions like
the ones that Steven showed. The only reason I can think of is the C#
design team's guiding philosophy that the language should be relatively
lean* and that each construct should be simple and do just one thing.

* I realize that if you compare C# to some other object-oriented
languages it comes off looking bloated by comparison. Here I'm talking
about the differences between C# and VB.NET.
 
B

Bruce Wood

No, but if you eat antepasto and pasta at the same meal, the calories
cancel each other out. Italians are clever that way. ;)
 
N

Nick Hounsome

ME said:
Bruce,

I agree with your logic. So the next question I would have is why does VB
still allow it? Shouldn't the languages be close here? The diffence
between a dynamic construct(vb) and a static one could cause some major
grief if re-wrote from VB to C#.

Major grief? Just rewrite as if...else if...else
You've obviuously had a very easy life if that is major grief.
It could be said that this WOULD make C# a better language.

But it ISN'T said except by VB programmers.
Isn't that what MS is trying to squash?

I doubt it.
Thanks,

Matt

It could be said that switch is an anachronism in a modern language and that
it should be eliminated altogether. Modern compilers should be smart enough
to turn either construct into the other wherever applicable thus making it
merely an alternate syntax.

The one semantic difference C# switch seems to have compared to VB (I'm not
a VB programmer) and if..elseif..else is that C# cases must be mutually
exclusive whereas it would appear that VB's do not. This implies that the
"correct" solution is to eliminate switch from VB where it is redundant but
not from C# where it is not :)
 
G

Guest

Hmmm...

You asked "why (VB does and C# doesn't)?" History - most likely. VB6 select is dynamic so VB.Net is; C++ switch is static (and I don't know Java enough to say how _it_ behaves) - and C# was written to be C++'s successor - so its switch is similarly static.

Yep - it would be nice if VB's select was available in C#. The closest you can come, however, is to implement the dynamic switch in VB.Net as the smallest object you can write that does what you want - and consume it from C#. Without knowing all of what you're trying to do, I'd write (in VB.Net) a delegate function that does the select and returns an enum value depending on the result of the dynamic select; I'd then use switch in C# to invoke the desired behavior based on the returned enum value.

HTH,
Chris
I can see the enum example is throwing several off the point. Here is another EXAMPLE of a time when I would like to use a dynamic switch:

private void WorkWithSelectedColumn(TemplateADataSet.SiteOptionsRow row, string columnName)
{

//Switch 1 works:
switch (columnName)
{
case "Key":
break;
case "Value":
break;
case "UniqueID":
break;
}

//Switch 2 does not work in c# but the vb version will work
switch (columnName)
{
case row.Key:
break;
case row.Value:
break;
case row.UniqueID:
break;
}
}

I realize that C# requires a constant. My question is, why give the VB guys the "option" of creating a dynamic switch/select case but not give it to the C# guys? Typically the way I handle this particular example is by using SQL to generate some code constants (public constants of every column name of every table in my data base) and use those in place of the "xxx" in switch 1. It would be nice to be able to perform the task in switch 2, which would leave out a step (VS builds the dataset for me just fine).

Thanks,

Matt
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top