Кто-нибудь до сих пор использует [goto] в C #, и если да, то почему? [закрыто]

104

Мне было интересно, использует ли кто-нибудь еще синтаксис ключевого слова goto в C # и каковы возможные причины для этого.

Я склонен рассматривать любые утверждения, которые заставляют читателя прыгать по коду, как плохую практику, но задавался вопросом, существуют ли какие-либо вероятные сценарии использования такого синтаксиса?

Перейти к определению ключевого слова

Брайан Скотт
источник
3
что значит "еще"? Был ли период времени, когда люди использовали его все время [в C #]?
Massif
4
@Massif: «still» был призван подчеркнуть современное мнение об использовании «goto» в качестве прелюдии к спагетти-коду и недостаточной читабельности исходного кода. Очень редко вы видите какие-либо примеры кода, включающие это конкретное ключевое слово, поэтому я и хотел спросить в первую очередь.
Брайан Скотт
50
Если читатель «прыгает» по коду - плохая практика, то избегаете ли вы также «break», «continue», «throw» и «return»? Все они вызывают ветвь в потоке управления, иногда нелокальную ветвь. «Бросок» даже не говорит вам, куда он идет, в отличие от goto.
Эрик Липперт
2
Я использую, gotoчтобы разорвать цикл и вернуться к начальному утверждению в соответствии с определенным условием
Nitin S
3
Мне нравится goto. Я старался избегать этого, потому что люди часто говорят, что это нужно избегать, потому что это затрудняет чтение кода. Изучив язык ассемблера и операторы ветвления, я думаю, что иногда это может сделать код более читабельным. Я действительно думаю, что многократное использование одного метода и слишком глубокий прыжок в коде могут принести больше вреда, чем пользы. Но если вы думаете, что здесь будет хорошо работать goto, простое goto время от времени не должно заставлять вас изо всех сил избегать только потому, что общий консенсус состоит в том, чтобы избегать его.
eaglei22 05

Ответы:

93

Есть некоторые (редкие) случаи, когда goto действительно может улучшить читаемость. Фактически, документация, на которую вы ссылаетесь, приводит два примера:

Обычно goto используется для передачи управления определенной метке switch-case или метке по умолчанию в инструкции switch.

Оператор goto также полезен для выхода из глубоко вложенных циклов.

Вот пример последнего:

for (...) {
    for (...) {
        ...
        if (something)
            goto end_of_loop;
    }
}

end_of_loop:

Конечно, есть и другие способы решения этой проблемы, такие как рефакторинг кода в функцию, использование вокруг нее фиктивного блока и т. Д. ( Подробности см. В этом вопросе ). Кстати, разработчики языка Java решили полностью запретить goto и вместо этого ввести помеченный оператор break .

Heinzi
источник
49
Обычно я бы попытался реорганизовать это, чтобы поместить циклы в отдельный метод, из которого я мог бы просто вернуться ...
Джон Скит
2
@Heinzi - я не видел, чтобы goto было оправдано. Как говорит Джон, если это «оправдано», код требует реорганизации.
manojlds 01
29
помеченный break, просто более длинный способ сказать goto, потому что он делает ту же чертову вещь ....
Хесус Рамос
20
@Jesus, но с goto вы можете пойти куда угодно. Маркированный перерыв гарантирует, что вы выйдете за пределы цикла.
mihsathe 01
1
Если вы не любите приключения и не используете goto с адресом (я видел это раньше), эта проблема решается. И я сомневаюсь, что кто-то использует обходные крючки в вашем коде C # и Java для использования операторов goto.
Хесус Рамос
66

Я помню эту часть

switch (a)     
{ 
    case 3: 
        b = 7;
        // We want to drop through into case 4, but C# doesn't let us
    case 4: 
        c = 3;
        break; 
    default: 
        b = 2;
        c = 4;
        break; 
}

Что-то вроде этого

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

Обратитесь к этому

V4Vendetta
источник
17
На самом деле я считаю это наиболее веской причиной для использования [goto]. По крайней мере, в этом сценарии это увеличивает удобочитаемость для программистов, не подозревающих, что случаи переходят друг в друга без оператора break.
Брайан Скотт
11
@ Брайан Скотт, V4Vendetta. Если я не ошибаюсь, первый оператор не компилируется на C #. Это поможет понять программисту.
Джодрелл
2
V4Vendetta, почему вы вставили разрыв в первом фрагменте кода ...? Лучше было показать его без перерыва, иначе два фрагмента будут делать разные вещи. Причина, по которой вам нужен goto во втором примере, заключается именно в том, что первый не компилируется в C # (как в C).
Стивен Холт
23

Я широко использую его в Eduasync, чтобы показать тип кода, который компилятор генерирует для вас при использовании асинхронных методов в C # 5. Вы увидите то же самое в блоках итераторов.

Однако в "нормальном" коде я не могу вспомнить, когда использовал его в последний раз ...

Джон Скит
источник
1
Можете ли вы привести небольшой пример того, почему этот подход был предпочтительным или это было просто личным предпочтением?
Брайан Скотт
1
@ Брайан: Не совсем понятно, о чем ты. Eduasync показывает код C #, эквивалентный тому, что делает для вас компилятор, и генерирует код, который эффективно использует goto ...
Джон Скит
9

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

Хесус Рамос
источник
7
Конечно, «break» / «continue» - лучший подход к управлению циклом, чем требовать от редактора кода бегать по исходному коду, пытаясь понять, где происходит следующий шаг?
Брайан Скотт
6
Нет, если у вас есть вложенные циклы.
Хесус Рамос
1
хорошо, я считаю это допустимым сценарием.
Брайан Скотт
1
В случае ошибки вам следует подумать о создании исключения.
Джодрелл
6
Если вы хотите обработать ошибку внутренне без исключения, это будет допустимый способ сделать это.
Хесус Рамос
8

Я не помню, чтобы когда-либо использовал goto. Но, возможно, это улучшает намерение цикла forever, из которого вы действительно никогда не хотите выходить (нет break, но вы все равно можете returnили throw):

forever: {
  // ...
  goto forever;
}

Опять же, простого while (true)должно хватить ...

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

Жордау
источник
Связанный ответ содержит «интересное» использование goto.. и while(true) {..}не интересно использование ..
user2864740
5

Компилятор использует gotoоператоры в различных частях сгенерированного кода, например, в сгенерированных типах блоков итераторов (сгенерированных при использовании yield returnключевого слова - я почти уверен, что сгенерированные типы сериализации XML также имеют несколькоgoto где-то там операторов.

См. Подробности реализации блока итератора: автоматически сгенерированные конечные автоматыПодробнее о том, почему и как компилятор C # это обрабатывает, .

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

Смотрите заявление Go-to, считающееся вредным, как аргумент против, gotoа также классический фрагмент истории программирования.

Джастин
источник
4
Это глупо: есть несколько случаев, когда goto полезно, как показано другими ответами. Либо вы их явно теряете, либо просто говорите «это неправильно», что ж, неправильно.
о0 '.
@Lohoris Я не куплюсь на это - каждый пример, который я видел, где goto «улучшает читаемость» (включая ответы здесь), был бы намного более читабельным после некоторого простого рефакторинга.
Джастин
3
@ Просто нет, иногда вложенные циклы - это самый естественный способ что-то сделать, например, если вы просматриваете массив массивов.
о0 '.
6
@Justin не всегда проще включить его в функцию. Вы заставляете что-то (имея функцию) просто избежать того, что ненавидите религиозно (используя goto). Четкое указание на то, что вы делаете что-то не так.
о0 '.
3
Вызовы @Justin Functions имеют накладные расходы. gotoне. Что нужно учитывать.
Дэн Бечард,
2

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

Одним из преимуществ использования языков 3-го или 4-го поколения является то, что эти физические детали отделены от нас. Хотя мы должны помнить о законе дырявой абстракции, я думаю, что мы также должны использовать наши инструменты по назначению ( извините ). Если бы я писал код и gotoидея казалась хорошей, пора было бы провести рефакторинг. Цель структурированного языка - избежать этих «скачков» и создать логический поток в нашей разработке.

Я должен избегать использования, breakно я не могу не заметить преимущества в производительности. Однако, если у меня есть вложенные циклы, которые взаимно необходимы break, пора провести рефакторинг.

Если кто-то может предложить использовать gotoэто, кажется, лучше, чем рефакторинг, я с радостью отзову свой ответ.

Надеюсь, я не виноват в том, что бросился сюда в « велосипедный навес ». Как говорит Краген, того, что достаточно для Дейкстры, достаточно для меня.

Джодрелл
источник
1
Взять dynamicобъект и пройтись по его графу объектов, который содержит несколько словарей, чтобы перейти к нужным мне значениям. Нет смысла использовать методы, которые имеют параметр, dynamicно ожидают точной формы объекта. С goto, чтобы разбить несколько слоев и продолжить просмотр коллекции этих объектов. [Мне не принадлежат типы, поэтому я не могу предоставить лучший доступ, так что это отражение или динамическое]
Крис Марисич
-6

Гото никогда не бывает лучше. И continue, break (кроме switch / case), (множественный) return и throw также должны быть сведены к минимуму. Вы никогда не захотите сбежать из середины петли гнезда. Вы всегда хотите, чтобы операторы управления циклом имели все управление циклом. Отступы содержат информацию, и все эти утверждения отбрасывают эту информацию. С таким же успехом можно убрать все отступы.

Кирк Августин
источник
10
Вы хотели бы выйти из цикла, если нет смысла продолжать выполнение цикла. В противном случае вы без причины потратите больше времени на обработку в более длинных циклах.
Skuld
12
@ Кирк, это больше похоже на мнение, чем на что-то количественное?
Брайан Скотт,