Вопрос:
Ярлыки и GOTO считаются плохой практикой, и, насколько я знаю, нет смысла использовать ее в С#.
Что такое использование меток на С#?
Ответ №1
Нет ничего плохого в ярлыках и goto в себе. Проблема в том, что люди склонны злоупотреблять ими, что создает проблему.
Типичное использование метки
OperationStart: if ( !TrySomeOperation() ) { if ( MaybeFixOperation() ) { goto OperationStart; } }
Вам нужно будет сделать несколько утверждений о том, что вы не можете попасть в цикл infitite, но, учитывая разумный набор гарантий, в этом коде нет ничего неправильного.
Ответ №2
Просто потому, что они являются дискредитирующим практика, вовсе не означает, следует закрыть любую возможность их использования. Хотя они, возможно, никогда не потребуются, они иногда являются лучшим способом.
Ответ №3
Иногда проблемная область содержит множество состояний machiens (например, протоколы телекоммуникаций часто определяются конечными автоматами), большую часть времени вы часто не видите конечный автомат.
Gotos и ярлыки также очень полезны для машинного кода, если вы пишете простой компилятор, который выводит С#, вы можете быть очень рады им.
Ответ №4
Я думаю, что это было маркетинговое решение.
Microsoft хочет, чтобы все разработчики использовали свой язык С#, и если вы добавляете метки, это упрощает переход для некоторых программистов. Это также упрощает перенос старого кода на их язык…
Ответ №5
Ярлыки без goto бесполезны, они ничего не делают.
Использование goto считается плохой практикой. Но есть случай, когда его нельзя избежать: вырваться из вложенных циклов:
foreach(…) { foreach(…) { if(…) { goto OuterLabel; } } } OuterLabel:
В таком случае с помощью оператора break будет просто разбит самый внутренний цикл.
Ответ №6
Генераторы кода иногда используют метки и топологи. В некоторых случаях он может упростить логику генерации кода. Операции Goto обычно игнорируются по соображениям удобочитаемости, но если код не предназначен для чтения, то это спорный вопрос.
Я также видел случаи, когда декомпилятор достаточно запутывался IL и выводил операторы goto вместо хорошо продуманной последовательности инструкций, которые человек мог бы вызвать. Если операторы goto не были законными, то декомпилятор, возможно, должен был бы полностью использовать этот раздел кода. Таким образом, по крайней мере, он может генерировать что-то, что может быть отключено.
Ответ №7
Почему он там?
Причина на самом деле довольно проста. Ассемблер и ИЛ не поддерживают расширенные инструкции, такие как for, do, break, continue и while. Неявно, код, который петли (или, в более общем плане, ветки), скомпилирован в ветки. goto и label – очень буквальная ветвь.
Обратите внимание, что вы просто не можете реализовать все приспособления, о которых я могу легко думать без “goto” – хотя обычно есть лучшие альтернативы (в этот момент я хотел бы указать, что существуют шаблоны проектирования, такие как State pattern).
Если вы создаете такой язык, как С#, который является своего рода “ассемблером высокого уровня для IL”, имеет смысл поддерживать хотя бы все, что есть в IL. Здесь branch/label – это низкоуровневая конструкция, а goto/label – это проекция С# (с областью, добавленной как конструкция высокого уровня).
Из компилятора POV
В конце концов, если вы переходите к тому, как работает компилятор, есть разница в предсказуемом коде и непредсказуемом коде. Оптимизирующая часть компилятора тратит огромные усилия на нормализацию конструкций, которые вы используете в своем коде. После нормализации он оптимизирован с использованием шаблонов.
В этом и заключается проблема. Если у вас есть цикл while, цикл for или цикл foreach, он определенно генерирует нормализованный шаблон. В конце концов, петли – это номер один в вашем коде, который можно оптимизировать. Однако, если вы используете странные ветки, они не будут оптимизированы – просто потому, что они не будут нормализованы к стандартизованному шаблону и поэтому не будут подхватываться шаблоном.
Этот комментарий касается не только предсказуемости шаблонов кода, но и предсказуемости потока данных. Опять же, если это предсказуемо, ваш компилятор может сделать больше, чем если бы он не был. В различных случаях конструкции, такие как break и continue, также приводят к более непредсказуемым ветвям; ярлыки и goto просто доставят вас туда легче. Результат будет таким же: ваша производительность пострадает, если это произойдет.
Итак, хотя верно, что все компиляторы меняют петли на ветки определенной формы. Компилятор IL – это компилятор SSA, как LLVM. Это видео Чандлера объясняет кое-что о том, как это работает:
Ответ №8
Трудно делать инструкции switch без них.
Ответ №9
Я читал где-то, goto в большинстве случаев должен просто использоваться для перескакивания вперед, поэтому, скорее всего, только для ранних циклов окончания и для продолжения внешнего цикла, поскольку на С# нет меток с петлями (в отличие от Java). И есть некоторые алгоритмы, которые могут быть элегантно выражены с помощью goto, чем сделать это структурированным способом.
Ответ №10
Иногда хорошо выполненный “goto” является более элегантным/удобочитаемым, чем другие методы. Полагать, что “перешли, когда они не нужны, конечно, плохая практика. Как всегда, каждая ситуация должна быть тщательно оценена.
Например, “goto может быть приятным, когда ваша функция должна выполнять очистку в случае ее отказа. Вы помещаете метку в конце функции, где вы выполняете очистку, а затем” переходите” к ней в случае сбоя.
Тем не менее, “goto стали менее полезными в С#, чем в C. Например, правильное использование обработки исключений может устранить необходимость” goto “в некоторых сценариях.
Ответ №11
Использование меток заключается в поддержке goto. Плохо, поскольку goto может быть, если у вас есть goto на языке, тогда вам нужны метки. Без goto метки на самом деле бесполезны в С#.
Ответ №12
Хотя в принципе я считаю, что есть законные применения для оператора goto, на практике я развивался на С#, так как он был впервые выпущен, и я не знал, что он имел оператор goto до сих пор.
Ответ №13
Если (аудитория .LikesGoTo == true)
{ goto LabelThatSupportGoTo;
}
еще
{ goto LabelForRejectGoTo;
}