C# switch case style
-
In C# it is not legal (or compilable) to let execution fall thru from one
switch
case
context to another. I'm working on a piece of code to do a MouseHook in C#. Becuase it has to deal with win 32 API messages, I of course have a big longswitch
statement or two. An example is deciding which button spawned a particular message, based on the message ID. In good-ol' C/C++ you'd do it something like this:int button = 0;
switch ( wParam )
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
button = LEFT;
break;case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_RBUTTONDBLCLK:
button = RIGHT;
break;
//etc. etc.
}Well that won't compile in C# and given the nature of a C#
switch
statement I can see two alternatives.MouseButton button = MouseButtons.None;
switch ( wParam )
{
case WM_LBUTTONDOWN:
button = MouseButtons.Left;
break;
case WM_LBUTTONUP:
button = MouseButtons.Left;
break;
case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
break;case WM_RBUTTONDOWN:
button = MouseButtons.Right;
break;
case WM_RBUTTONUP:
button = MouseButtons.Right;
break;
case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
break;
//etc. etc.
}or something like :
MouseButton button = MouseButtons.None;
switch ( wParam )
{
case WM_LBUTTONDOWN:
goto case WM_LBUTTONDBLCLK;
case WM_LBUTTONUP:
goto case WM_LBUTTONDBLCLK;
case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
break;case WM_RBUTTONDOWN:
goto case WM_RBUTTONDBLCLK;
case WM_RBUTTONUP:
goto case WM_RBUTTONDBLCLK;
case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
break;
//etc. etc.
}Realizing that big
switch
statements are notoriously buggy and difficult to maintain, I'm torn between which flavor is less bad. We've all, of course, been schooled on the harmfulness ofgoto
, and the poor person who's got to debug that code four years from now is in for headache. On the other hand, without the goto's, you end up with a lot duplicate code (all the assignment statements in the above exaple), which always raises a red flag for me (especially because of the maintainance issues duplicate code can cause). Anybody got an opinion on this? I'm leaning towards the non-goto version but am looking for other opinio -
In C# it is not legal (or compilable) to let execution fall thru from one
switch
case
context to another. I'm working on a piece of code to do a MouseHook in C#. Becuase it has to deal with win 32 API messages, I of course have a big longswitch
statement or two. An example is deciding which button spawned a particular message, based on the message ID. In good-ol' C/C++ you'd do it something like this:int button = 0;
switch ( wParam )
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
button = LEFT;
break;case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_RBUTTONDBLCLK:
button = RIGHT;
break;
//etc. etc.
}Well that won't compile in C# and given the nature of a C#
switch
statement I can see two alternatives.MouseButton button = MouseButtons.None;
switch ( wParam )
{
case WM_LBUTTONDOWN:
button = MouseButtons.Left;
break;
case WM_LBUTTONUP:
button = MouseButtons.Left;
break;
case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
break;case WM_RBUTTONDOWN:
button = MouseButtons.Right;
break;
case WM_RBUTTONUP:
button = MouseButtons.Right;
break;
case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
break;
//etc. etc.
}or something like :
MouseButton button = MouseButtons.None;
switch ( wParam )
{
case WM_LBUTTONDOWN:
goto case WM_LBUTTONDBLCLK;
case WM_LBUTTONUP:
goto case WM_LBUTTONDBLCLK;
case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
break;case WM_RBUTTONDOWN:
goto case WM_RBUTTONDBLCLK;
case WM_RBUTTONUP:
goto case WM_RBUTTONDBLCLK;
case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
break;
//etc. etc.
}Realizing that big
switch
statements are notoriously buggy and difficult to maintain, I'm torn between which flavor is less bad. We've all, of course, been schooled on the harmfulness ofgoto
, and the poor person who's got to debug that code four years from now is in for headache. On the other hand, without the goto's, you end up with a lot duplicate code (all the assignment statements in the above exaple), which always raises a red flag for me (especially because of the maintainance issues duplicate code can cause). Anybody got an opinion on this? I'm leaning towards the non-goto version but am looking for other opinioI don't understand. Your example of stacking up case labels does compile in C#. Here's a small example:
Random r = new Random(); switch (r.Next(10)) { case 1: Console.WriteLine("It's one"); break; case 2: case 3: case 5: case 7: Console.WriteLine("It's prime"); break; default: Console.WriteLine("It's composite"); break; }
Cheers, Julian Program Manager, C# This posting is provided "AS IS" with no warranties, and confers no rights.
-
I don't understand. Your example of stacking up case labels does compile in C#. Here's a small example:
Random r = new Random(); switch (r.Next(10)) { case 1: Console.WriteLine("It's one"); break; case 2: case 3: case 5: case 7: Console.WriteLine("It's prime"); break; default: Console.WriteLine("It's composite"); break; }
Cheers, Julian Program Manager, C# This posting is provided "AS IS" with no warranties, and confers no rights.
I was getting an error when I was setting up a switch block, and on further examination it looks like it was because I failed to include a break in my default case. Without the break in the last case statement you get something like: "error CS0163: Control cannot fall through from one case label ('case 2:') to another" However, when I first encountered the error I found this in the C# MSDN reference on the switch statement: "Unlike the C++ switch statement, C# does not support an explicit fall through from one case label to another. If you want, you can use goto a switch-case, or goto default." Now I'm confused, because that apparently doesn't mean what I thought it meant. The way I read the statement from MSDN, plus if you read the help on error number CS0163 (see reference below), it seems to support my original post. It seems like either the C# help is in error, or the compiler is in error (or I'm just plain missing something). :confused: don References Error CS0163: ms-help://MS.VSCC.2003/MS.MSDNQTR.2003JUL.1033/cscomp/html/vcerrCompilerErrorSC0163.htm Switch statement help: ms-help://MS.VSCC.2003/MS.MSDNQTR.2003JUL.1033/csref/html/vclrfTheSwitchStatement.htm
-
I was getting an error when I was setting up a switch block, and on further examination it looks like it was because I failed to include a break in my default case. Without the break in the last case statement you get something like: "error CS0163: Control cannot fall through from one case label ('case 2:') to another" However, when I first encountered the error I found this in the C# MSDN reference on the switch statement: "Unlike the C++ switch statement, C# does not support an explicit fall through from one case label to another. If you want, you can use goto a switch-case, or goto default." Now I'm confused, because that apparently doesn't mean what I thought it meant. The way I read the statement from MSDN, plus if you read the help on error number CS0163 (see reference below), it seems to support my original post. It seems like either the C# help is in error, or the compiler is in error (or I'm just plain missing something). :confused: don References Error CS0163: ms-help://MS.VSCC.2003/MS.MSDNQTR.2003JUL.1033/cscomp/html/vcerrCompilerErrorSC0163.htm Switch statement help: ms-help://MS.VSCC.2003/MS.MSDNQTR.2003JUL.1033/csref/html/vclrfTheSwitchStatement.htm
Ah ha! You're reading the "simplified" pages and I'm not surprised that you found ambiguity. Personally I tend to go to the authoritative source, the C# Language Reference. Here you see that a switch statement consists of "switch" followed by an expression in parentheses followed by a switch block a switch block consists of 0 or more switch sections, the whole wrapped in braces a switch section consists of one or more switch labels followed by a list of statements a switch label is either "case" followed by a constant expression followed by colon, or "default" followed by colon. It is the statement list that cannot "fall through." (In fact, it's stated as "the end point of a statement list cannot be reachable," by which it means that you cannot get to the point just after the last statement in the statement list. In other words, the last statement in the list must be a "jump" type statement: break, goto, throw, etc.) Hence, , you can have code that lokos like this: switch (foo) { case 1: case 2: DoSomething(); break; ... } As to the error message, I agree that it could be a little misleading, although it does correctly talk about the last switch label in the (possible) list of labels. Cheers, Julian Program Manager, C# This posting is provided "AS IS" with no warranties, and confers no rights.
-
Ah ha! You're reading the "simplified" pages and I'm not surprised that you found ambiguity. Personally I tend to go to the authoritative source, the C# Language Reference. Here you see that a switch statement consists of "switch" followed by an expression in parentheses followed by a switch block a switch block consists of 0 or more switch sections, the whole wrapped in braces a switch section consists of one or more switch labels followed by a list of statements a switch label is either "case" followed by a constant expression followed by colon, or "default" followed by colon. It is the statement list that cannot "fall through." (In fact, it's stated as "the end point of a statement list cannot be reachable," by which it means that you cannot get to the point just after the last statement in the statement list. In other words, the last statement in the list must be a "jump" type statement: break, goto, throw, etc.) Hence, , you can have code that lokos like this: switch (foo) { case 1: case 2: DoSomething(); break; ... } As to the error message, I agree that it could be a little misleading, although it does correctly talk about the last switch label in the (possible) list of labels. Cheers, Julian Program Manager, C# This posting is provided "AS IS" with no warranties, and confers no rights.
And the light comes on! It does makes sense now (and also renders my original post completely moot). Thanks for clearing up the ambiguity for me Julian! don To summarize legal:
switch case( foo )
{
case 0:
case 1:
DoIt();
break;
}not-legal:
switch ( foo )
{
case 0:
DoOneThing();
case 1:
DoAnotherThing();
break;
}also not legal:
switch ( foo )
{
case 0:
DoOneThing();
break;
default:
DoAnotherThing();
// need break here
}