I've seen a suggested coding standard that reads Never use goto unless in a switch statement fall-through
.
I don't follow. What exactly would this 'exception' case look like, that justifies a goto
?
I've seen a suggested coding standard that reads Never use goto unless in a switch statement fall-through
.
I don't follow. What exactly would this 'exception' case look like, that justifies a goto
?
This construct is illegal in C#:
switch (variable) {
case 2:
Console.WriteLine("variable is >= 2");
case 1:
Console.WriteLine("variable is >= 1");
}
In C++, it would run both lines if variable = 2
. It may be intentional but it's too easy to forget break;
at the end of the first case label. For this reason, they have made it illegal in C#. To mimic the fall through behavior, you will have to explicitly use goto
to express your intention:
switch (variable) {
case 2:
Console.WriteLine("variable is >= 2");
goto case 1;
case 1:
Console.WriteLine("variable is >= 1");
break;
}
That said, there are a few cases where goto
is actually a good solution for the problem. Never shut down your brain with "never use something" rules. If it were 100% useless, it wouldn't have existed in the language in the first place. Don't use goto
is a guideline; it's not a law.
C# refuses to let cases fall through implicitly (unless there is no code in the case) as in C++: you need to include break
. To explicitly fall through (or to jump to any other case) you can use goto case
. Since there is no other way to obtain this behaviour, most (sensible) coding standards will allow it.
switch(variable)
{
case 1:
case 2:
// do something for 1 and 2
goto case 3;
case 3:
case 4:
// do something for 1, 2, 3 and 4
break;
}
A realistic example (by request):
switch(typeOfPathName)
{
case "relative":
pathName = Path.Combine(currentPath, pathName);
goto case "absolute";
case "expand":
pathName = Environment.ExpandEnvironmentVariables(pathName);
goto case "absolute";
case "absolute":
using (var file = new FileStream(pathName))
{ ... }
break;
case "registry":
...
break;
}
public enum ExitAction {
Cancel,
LogAndExit,
Exit
}
This is neater
ExitAction action = ExitAction.LogAndExit;
switch (action) {
case ExitAction.Cancel:
break;
case ExitAction.LogAndExit:
Log("Exiting");
goto case ExitAction.Exit;
case ExitAction.Exit:
Quit();
break;
}
Than this (especially if you do more work in Quit())
ExitAction action = ExitAction.LogAndExit;
switch (action) {
case ExitAction.Cancel:
break;
case ExitAction.LogAndExit:
Log("Exiting");
Quit();
break;
case ExitAction.Exit:
Quit();
break;
}
It's the only way that C# allows a switch case 'fallthrough'. In C# (unlike C, C++ , or Java), a case block in a switch statement must end with a break
or some other explicit jump statement.
In addition to using goto case
, you can goto
a label that is in another case clause:
switch(i) {
case "0":
// do some stuff
break;
case "1":
// other stuff, then "fall through" to next case clause
goto Case2;
case "2":
Case2:
break;
}
This way, you can jump to another case clause without worrying about the value or type of the expression.
Some sort of explicit "fallthrough" keyword that can be substituted for break
would have been nice, though...
By way of an extension to Mehrdad Afshari's advice above, I would never advocate simply exiling a construct as 'bad code' or 'bad coding practice'. Even 'goto' statements have their place in the grand scheme of things. The dogma that they are evil did not come to pass because of any inherent flaw in the construct - it was because they were heavily (and poorly) over-used.
In any case, Kernighan and Ritchie felt that allowing a case to fall through was the proper way to go. Frankly, I'm more inclined to trust their reasoning than anything that could conceivably come out of any mind in the whole of Redmond, Washington. Or any dogma that is predicated on the wisdom of any mind in Redmond.
If you ever hear 'Never use xxx', mentally append that with 'without cause'. Just tossing out anything dogmatically is ridiculous. Devices exist because there was a reason to make them. They are, in hindsight, usually referred to as 'bad' not because of any fault in the device itself, but rather because they were employed poorly by people who did not fully understand them. Thus, the device is hardly ever 'bad'. What is almost always bad is user comprehension. This is true even of atomic fission and fusion.
I've seen horrendously grotesque code structures whose sole function was to avoid the use of a 'goto' statement. What is worse? "goto [label]", or 30 lines of disgusting code whose function is to avoid having to type "goto [label]"?
Seek knowledge before dogma. Think before you act. These are useful advices.