Использовать 'goto' в переключателе? - PullRequest
46 голосов
/ 21 января 2011

Я видел предложенный стандарт кодирования, который гласит: Never use goto unless in a switch statement fall-through.

Я не следую.Как именно выглядел бы этот случай «исключения», который оправдывает goto?

Ответы [ 6 ]

91 голосов
/ 21 января 2011

Эта конструкция недопустима в C #:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
   case 1:
       Console.WriteLine("variable is >= 1");
}

В C ++ он будет запускать обе строки, если variable = 2. Это может быть преднамеренным, но слишком легко забыть break; в конце первой метки. По этой причине они сделали это незаконным в C #. Чтобы имитировать поведение при падении, вы должны явно использовать goto, чтобы выразить свое намерение:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
       goto case 1;
   case 1:
       Console.WriteLine("variable is >= 1");
       break;
}

Тем не менее, есть несколько случаев , где goto на самом деле является хорошим решением проблемы. Никогда не закрывайте свой мозг с правилами "никогда не используйте что-то". Если бы он был на 100% бесполезен, его бы изначально не было в языке. Не используйте goto рекомендацию ; это не закон.

21 голосов
/ 21 января 2011

C # отказывается позволить неявно проваливать дела (если в деле нет кода), как в C ++: вам нужно , чтобы включить 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;
}
7 голосов
/ 21 января 2011
   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;
}
4 голосов
/ 11 февраля 2012

Помимо использования goto case, вы можете goto метку, которая находится в другом предложении case:

    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, было бы неплохо, хотя ...

4 голосов
/ 21 января 2011

Это единственный способ, с помощью которого C # допускает случайный случай переключения.В C # (в отличие от C, C ++ или Java) блок case в операторе switch должен заканчиваться break или некоторым другим явным оператором jump.

1 голос
/ 27 ноября 2015

В качестве дополнения к совету Мехрада Афшари, приведенному выше, я бы никогда не рекомендовал просто изгнать конструкцию как «плохой код» или «плохую практику кодирования». Даже заявления «goto» имеют свое место в общей схеме вещей. Догма о том, что они злые, не сбылась из-за какого-либо врожденного недостатка конструкции - это было потому, что они были сильно (и плохо) чрезмерно использованы.

В любом случае, Керниган и Ричи считали, что позволить делу провалиться - это правильный путь. Честно говоря, я больше склонен доверять их рассуждениям, чем всему, что могло бы прийти в голову во всем Редмонде, штат Вашингтон. Или любая догма, основанная на мудрости любого ума в Редмонде.

Если вы когда-нибудь услышите «Никогда не используйте xxx», мысленно добавьте это «без причины». Просто выбрасывать что-либо догматично - смешно. Устройства существуют, потому что была причина, чтобы сделать их. В ретроспективе их обычно называют «плохими» не из-за какой-либо неисправности самого устройства, а скорее потому, что их плохо использовали люди, которые их не полностью понимали. Таким образом, устройство вряд ли когда-либо «плохое». Что почти всегда плохо, так это пользователь понимание . Это верно даже для атомного деления и синтеза.

Я видел ужасно гротескные структуры кода, единственной функцией которых было избежать использования оператора 'goto'. Что хуже? "goto [метка]", или 30 строк отвратительного кода, функция которого состоит в том, чтобы избежать ввода "goto [метка]"?

Ищите знания перед догмой. Думай прежде чем сделать. Это полезные советы.

...