Перейти к оператору, продуманному вредный?

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

Править: позвольте мне перефразировать: все ДВИЖЕНИЕ-TO's, я вижу в отражателе, записанном людьми или компиляторами?

16
задан Yaron Naveh 22 March 2010 в 19:05
поделиться

12 ответов

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

19
ответ дан 30 November 2019 в 15:05
поделиться

Я иногда использую 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 , я отправляю его в последнюю строку, которая выполняет другое последнее действие, на которое я могу ссылаться из разных мест во фрагменте, вместо того, чтобы просто завершить .

1
ответ дан 30 November 2019 в 15:05
поделиться

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

4
ответ дан 30 November 2019 в 15:05
поделиться

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

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

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


В ответ на вашу правку:

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

11
ответ дан 30 November 2019 в 15:05
поделиться

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

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

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

2
ответ дан 30 November 2019 в 15:05
поделиться

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

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

Итак, Reflector смотрит на код примерно так:

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

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

 while (a > b)
    DoStuff();

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

8
ответ дан 30 November 2019 в 15:05
поделиться

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

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

1
ответ дан 30 November 2019 в 15:05
поделиться

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

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

Итак, с одной стороны, у нас есть Эдсгер Дейкстра (невероятно талантливый ученый-компьютерщик), который возражает против использования утверждения GOTO и, в частности, утверждает против чрезмерного использования оператора GOTO на том основании, что это гораздо менее структурированный способ написания кода.

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

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

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

24
ответ дан 30 November 2019 в 15:05
поделиться

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

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

Поверьте ...

Чтение другого кода с goto в нем ТРУДНО.
Чтение собственного кода с goto в нем ТРУДЧЕ.

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

1
ответ дан 30 November 2019 в 15:05
поделиться

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

Это не имеет ничего общего с вредностью goto.

4
ответ дан 30 November 2019 в 15:05
поделиться

Вредно это или нет, это вопрос симпатий и антипатий каждого. Мне лично они не нравятся, и я считаю их очень непродуктивными, поскольку они пытаются поддерживать код.

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

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

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

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

0
ответ дан 30 November 2019 в 15:05
поделиться

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

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

1
ответ дан 30 November 2019 в 15:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: