Перейти к заявлению считается вредным? - PullRequest
16 голосов
/ 21 марта 2010

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

РЕДАКТИРОВАТЬ: позвольте мне перефразировать: все GO-TO, которые я вижу в отражателе, написаны людьми или компиляторами?

Ответы [ 15 ]

24 голосов
/ 21 марта 2010

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

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

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

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

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

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

19 голосов
/ 21 марта 2010

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

11 голосов
/ 21 марта 2010

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

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

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


В ответ на ваши изменения:

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

8 голосов
/ 21 марта 2010

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

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

Итак, Reflector выглядит примерно так:

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

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

 while (a > b)
    DoStuff();

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

4 голосов
/ 21 марта 2010

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

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

4 голосов
/ 21 марта 2010

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

3 голосов
/ 31 октября 2012

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

 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
    }
2 голосов
/ 21 марта 2010

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

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

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

1 голос
/ 27 марта 2010

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

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

1 голос
/ 21 марта 2010

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

- K & R (2-е изд.): Стр. 65

...