Подтвердить что ты не робот

Перейти к заявлению считается вредным?

Если приведенное выше утверждение правильное, то почему, когда я использую рефлектор на .Net BCL, я вижу, что он используется много?

EDIT: позвольте мне перефразировать: все ли GO-TO я вижу в отражателе, написанном людьми или компиляторами?

4b9b3361

Ответ 1

Вышеуказанное не совсем правильно - это было полемическое устройство, используемое Dijkstra в то время, когда gotos были единственной структурой управления потоком в использовании. Фактически, несколько человек произвели опровержения, в том числе классическую классику Кнута "Структурированное программирование с помощью Goto" (название из памяти). И есть некоторые ситуации (обработка ошибок, конечные машины), где gotos могут создавать более четкий код (IMHO), чем "структурированные" альтернативы.

Ответ 2

Я думаю, что следующий отрывок из статьи Wikipedia о Goto особенно важен здесь:

Вероятно, самая известная критика GOTO - письмо от Эдсгера 1968 года Дейкстра называется Go To Statement Считается вредным. В этом письме Дейкстра утверждал, что неограниченный GOTO заявления должны быть отменены из языки более высокого уровня, потому что они усложнили задачу анализа и проверка правильности программ (особенно те, которые связаны с циклами). Представлена ​​альтернативная точка зрения в Дональд Кнут Структурированный Программирование с переходом к заявлениям который анализирует многие распространенные программы задач и находит, что в некоторых из них GOTO - это оптимальная языковая конструкция для использования.

Итак, с одной стороны, мы Edsger Dijkstra (невероятно талантливый компьютерный ученый), выступая против использования инструкции GOTO и, в частности, против использования чрезмерного оператора GOTO на том основании, что это гораздо менее структурированный способ написания кода.

С другой стороны, у нас есть Дональд Кнут (еще один невероятно талантливый компьютерный ученый), утверждающий, что использование GOTO, особенно используя его, можно разумно на самом деле быть "лучшей" и наиболее оптимальной конструкцией для данной части программного кода.

В конечном счете, ИМХО, я считаю, что оба человека верны. Dijkstra прав, поскольку чрезмерное использование оператора GOTO, безусловно, делает фрагмент кода менее читаемым и менее структурированным, и это, безусловно, верно при просмотре компьютерного программирования с чисто теоретической точки зрения.

Однако Кнут также правилен, так как в "реальном мире" , где нужно принять прагматичный подход, оператор GOTO, когда он используется мудро, действительно может быть лучшим выбором используемой конструкции языка.

Ответ 3

Эти goto очень часто генерируются компилятором, особенно внутри счетчиков. Компилятор всегда знает, что она делает.

Если вам нужно использовать goto, вы должны убедиться, что это единственный вариант. Чаще всего вы найдете там лучшее решение.

Кроме того, существует очень мало примеров использования goto, которые могут быть оправданы, например, при использовании вложенных циклов. Опять же, в этом случае есть другие варианты. Вы можете разбить внутренний цикл в функции и вместо этого использовать оператор return. Вам нужно посмотреть внимательно, если вызов дополнительного метода действительно слишком дорогостоящий.


В ответ на ваше редактирование:

Нет, не все gotos генерируются компилятором, но многие из них происходят из созданных компилятором состояний машин (счетчиков), операторов case case или оптимизированных структур if else. Есть только несколько примеров, которые вы сможете оценить, был ли он компилятором или оригинальным разработчиком. Вы можете получить хороший совет, посмотрев имя функции/класса, компилятор будет генерировать "запрещенные" имена, чтобы избежать конфликтов имен с вашим кодом. Если все выглядит нормально, и код не был оптимизирован или запутан, использование goto, вероятно, предназначено.

Ответ 4

Имейте в виду, что код, который вы видите в Reflector, является дизассемблером. Reflector смотрит на скомпилированные байтовые коды и пытается собрать исходный исходный код.

При этом вы должны помнить, что правила против goto применяются к высокоуровневому коду. Все конструкции, которые используются для замены goto (for, while, break, switch и т.д.), Все сводятся к коду с использованием JMP.

Итак, Reflector выглядит так:

A:
    if !(a > b)
        goto B;
    DoStuff();
    goto A;
B:  ...

И должен понять, что он был фактически закодирован как:

 while (a > b)
    DoStuff();

Иногда код считывается слишком сложным для распознавания шаблона.

Ответ 5

Go To сам по себе не является вредным, иногда даже очень полезно. Вредными являются пользователи, которые склонны помещать их в несоответствующие места в своем коде.

Ответ 6

При компиляции до кода сборки все элементы управления структурированы и преобразованы в (un) условные переходы. Однако оптимизатор может быть слишком сильным, и когда дизассемблер не может определить, какая структура управления соответствует шаблону перехода, будет выведено всегда правильное утверждение, т.е. goto label;.

Это не имеет никакого отношения к вреду (не более) меньше goto.

Ответ 7

как насчет двойной петли или многих вложенных циклов, из которых вы вырвались, например.

 foreach (KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
            {
                foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
                {
                    RefreshProgress("Daten werden geändert...", count++, false);

                    if (IsProgressCanceled)
                    {
                        goto TheEnd; //I like goto :)
                    }
                }
            }
TheEnd:

в этом случае вам следует подумать, что здесь нужно сделать следующее:

  foreach(KeyValuePair<DateTime, ChangedValues> changedValForDate in _changedValForDates)
    {
                    foreach (KeyValuePair<string, int> TypVal in changedValForDate.Value.TypeVales)
                    {
                        RefreshProgress("Daten werden geändert...", count++, false);

                        if (IsProgressCanceled)
                        {
                            break; //I miss goto :|
                        }
                    }

                 if (IsProgressCanceled)
                 {
                            break; //I really miss goto now :|
                 }//waaaAA !! so many brakets, I hate'm
    }

Ответ 8

Общее правило заключается в том, что вам не нужно использовать goto. Как и в случае с любым правилом, есть, конечно, исключения, но, как и при любых исключениях, их немного.

Команда goto похожа на наркотик. Если он используется в ограниченных количествах только в особых ситуациях, это хорошо. Если вы используете слишком много времени, это разрушит вашу жизнь.

Когда вы обдумываете код с помощью Reflector, вы не видите фактический код. Вы видите код, который воссоздан от того, что был создан компилятором из исходного кода. Когда вы видите goto в обновленном коде, он не уверен, что в исходном коде был goto. Может быть более структурированная команда для управления потоком, например, break или continue, которая была реализована компилятором так же, как и goto, так что Reflector не может отличить эту информацию.

Ответ 9

goto считается вредным (для человека использовать, но для компьютеров это нормально).

потому что независимо от того, насколько безумно мы (человек) используем goto, компилятор всегда знает, как читать код.

Поверь мне...

Чтение другого кода с помощью goto в нем HARD.
Чтение собственного кода с помощью goto в нем HARDER.

Вот почему вы видите, что он используется на низком уровне (машинные языки), а не на высоком уровне (человеческие языки, например С#, Python...);)

Ответ 10

Я иногда использую goto, когда хочу выполнить действие завершения:

static void DoAction(params int[] args)
{
  foreach (int arg in args)
  {
    Console.WriteLine(arg);
    if (arg == 93) goto exit;
  }

  //edit:
  if (args.Length > 3) goto exit;
  //Do another gazillion actions you might wanna skip.

  //etc.
  //etc.

exit:
  Console.Write("Delete resource or whatever");
}

Поэтому вместо того, чтобы нажимать return, я отправляю его на последнюю строку, которая выполняет другое заключительное действие, которое я могу ссылаться из разных мест в фрагменте, а не просто на завершение.

Ответ 11

"C предоставляет бесконечно оскорбительную инструкцию goto и метки для ветвления. Формально, goto никогда не требуется, и на практике почти всегда легко писать код без него. Мы не использовали goto в этой книге."

- K & R (2-е изд.): Page 65

Ответ 12

В декомпилированном коде практически все goto, которые вы видите, будут синтетическими. Не беспокойтесь о них; они являются артефактом того, как код представлен на низком уровне.

Что касается обоснованных причин для их ввода в свой собственный код? Главное, о чем я могу думать, это то, где язык, который вы используете, не обеспечивает конструкцию управления, подходящую для проблемы, которую вы решаете; языки, которые упрощают создание пользовательских систем управления потоком, обычно не имеют goto вообще. Также всегда можно вообще избегать их использования, но переставляя произвольно сложный код в цикл while и множество условных обозначений с целой батареей управляющих переменных... что может фактически сделать код еще более неясным (и медленнее тоже, компиляторы обычно недостаточно умны, чтобы разобрать такую ​​сложность). Основная цель программирования должна заключаться в создании описания программы, которая понятна для компьютера и для людей, читающих его.

Ответ 13

Если это вредно или нет, это вопрос симпатий и антипатий к каждому из них. Я лично их не люблю и считаю их очень непродуктивными, поскольку они пытаются поддерживать код кода.

Теперь, одна вещь заключается в том, как gotos влияют на наше чтение кода, в то время как другое - то, как работает дрожание при его обнаружении. Из Блог Эрика Липперта, я хотел бы процитировать:

Сначала мы запускаем проход для преобразования петель в gotos и метки.

Таким образом, на самом деле компилятор преобразует симпатичную структуру управления потоком в диаграмму goto/label при испускании IL. Когда отражатель считывает IL сборки, он распознает шаблон и преобразует его обратно в соответствующую структуру управления потоком.

В некоторых случаях, когда испускаемый код слишком сложный для понимания отражателем, он просто показывает вам код С#, который использует метки и gotos, что эквивалентно чтению IL. Это имеет место, например, при реализации методов IEnumerable<T> с операторами yield return и yield break. Эти методы преобразуются в их собственные классы, реализующие интерфейс IEnumerable<T>, используя базовый конечный автомат. Я верю в BCL, что вы найдете много таких случаев.

Ответ 14

GOTO может быть полезен, если он не используется чрезмерно, как указано выше. Microsoft даже использует его в нескольких экземплярах в самой .NET Framework.

Ответ 15

Эти goto очень часто генерируются компилятором, особенно внутри счетчиков. Компилятор всегда знает, что она делает.

Если вы обнаружили необходимость использования goto, вы должны убедиться, что это единственный вариант. Чаще всего вы найдете там лучшее решение.

Кроме того, очень мало примеров использования goto можно обосновать, например, при использовании вложенных циклов. Опять же, в этом случае есть другие варианты. Вы можете разбить внутренний цикл в функции и вместо этого использовать оператор return. Вам нужно посмотреть внимательно, если вызов дополнительного метода действительно слишком дорогостоящий.