Я видел предложенный стандарт кодирования, который читает Never use goto unless in a switch statement fall-through
.
Я не следую. Каково было бы это дело "исключение", что оправдывает goto
?
Я видел предложенный стандарт кодирования, который читает Never use goto unless in a switch statement fall-through
.
Я не следую. Каково было бы это дело "исключение", что оправдывает goto
?
Эта конструкция является незаконной в С#:
switch (variable) {
case 2:
Console.WriteLine("variable is >= 2");
case 1:
Console.WriteLine("variable is >= 1");
}
В С++ он будет запускать обе строки, если variable = 2
. Это может быть преднамеренным, но слишком легко забыть break;
в конце метки первого случая. По этой причине они сделали это незаконным в С#. Чтобы воспроизвести падение поведения, вам нужно явно использовать goto
, чтобы выразить свое намерение:
switch (variable) {
case 2:
Console.WriteLine("variable is >= 2");
goto case 1;
case 1:
Console.WriteLine("variable is >= 1");
break;
}
Тем не менее, есть несколько случаев, где goto
на самом деле является хорошим решением проблемы. Никогда не закрывайте свой мозг с правилами "никогда не используйте что-то". Если бы это было на 100% бесполезно, вначале оно не существовало бы на этом языке. Не использовать goto
является ориентиром; это не закон.
С# отказывается позволять случаям проходить неявно (если в коде нет кода), как в С++: вам нужно включить break
. Чтобы явно провалиться (или перейти в любой другой случай), вы можете использовать goto case
. Поскольку нет другого способа получить это поведение, большинство (разумных) стандартов кодирования позволят это.
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;
}
Реалистичный пример (по запросу):
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
}
Это аккуратно
ExitAction action = ExitAction.LogAndExit;
switch (action) {
case ExitAction.Cancel:
break;
case ExitAction.LogAndExit:
Log("Exiting");
goto case ExitAction.Exit;
case ExitAction.Exit:
Quit();
break;
}
Чем это (особенно если вы больше работаете в Quit())
ExitAction action = ExitAction.LogAndExit;
switch (action) {
case ExitAction.Cancel:
break;
case ExitAction.LogAndExit:
Log("Exiting");
Quit();
break;
case ExitAction.Exit:
Quit();
break;
}
В дополнение к использованию goto case
вы можете goto
метку, которая находится в другом случае:
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;
}
Таким образом, вы можете перейти к другому аргументу case, не беспокоясь о значении или типе выражения.
Некоторое явное ключевое слово "fallthrough", которое может быть заменено на break
, было бы неплохо, хотя...
Это единственный способ, с помощью которого С# разрешает случай переключения "провал". В С# (в отличие от C, С++ или Java) блок case в операторе switch должен заканчиваться на break
или какой-либо другой явный оператор перехода.
есть пример в http://msdn.microsoft.com/en-us/library/06tc147t%28v=vs.71%29.aspx
В качестве дополнения к совету Mehrdad Afshari, выше, я бы никогда не выступал просто изгнанием конструкции как "плохой код" или "плохая практика кодирования". Даже "goto" заявления имеют свое место в великой схеме вещей. Догма о том, что они злые, не сбылась из-за каких-либо присущих изъянов в конструкции - это было из-за того, что они были сильно (и плохо) чрезмерно использованы.
В любом случае, Керниган и Ричи чувствовали, что разрешить случай проваливаться - это правильный путь. Честно говоря, я более склонен доверять их рассуждениям, чем все, что могло бы возникнуть из любого ума во всем Редмонде, штат Вашингтон. Или любая догма, которая основана на мудрости любого ума в Редмонде.
Если вы когда-либо слышали "Никогда не используйте xxx", мысленно добавьте это с помощью "без причины". Просто бросать что-нибудь догматически смешно. Устройства существуют, потому что есть причина их создания. Они, оглядываясь назад, обычно называются "плохими" не из-за какой-либо ошибки в самом устройстве, а скорее из-за плохого использования людьми, которые не понимали их полностью. Таким образом, устройство вряд ли "плохо". То, что почти всегда плохо, - это понимание пользователем. Это справедливо даже при делении и слиянии атомов.
Я видел ужасно гротескные структуры кода, единственной функцией которых было избежать использования оператора 'goto'. Что еще хуже? "goto [label]" или 30 строк отвратительного кода, функция которого заключается в том, чтобы не набирать "goto [label]"?
Ищите знания до догмы. Думай прежде чем сделать. Это полезные советы.
Я знаю, что это старая тема, но вопрос все еще актуален. Можем ли мы использовать следующий код вместо уродливой версии с оператором goto?
var variable = 2;
switch (variable)
{
case 2:
Console.WriteLine("variable is >= 2");
goto case 1;
case 1:
Console.WriteLine("variable is >= 1");
break;
}
может быть заменен следующим кодом:
if (variable >= 2)
{
Console.WriteLine("variable is >= 2");
}
if (variable >= 1)
{
Console.WriteLine("variable is >= 1");
}