Goto заявления и альтернативы в VB.NET
я опубликовал фрагмент кода на другом форуме с просьбой о помощи, и люди указали мне, что с помощью GoTo
операторы-очень плохая практика программирования. Мне интересно: почему это плохо?
какие альтернативы GoTo
есть использовать в VB.NET что будет считаться вообще еще лучше практика?
рассмотрим этот фрагмент ниже, где пользователь должен ввести свою дату рождения. Если месяц / дата / год недействительны или нереалистичны, я хотел бы сделать цикл снова и снова просить пользователей. (Я использую операторы if для проверки размера целого числа... если есть лучший способ сделать это, я был бы признателен, если бы вы сказали мне, что также :D)
retryday:
Console.WriteLine("Please enter the day you were born : ")
day = Console.ReadLine
If day > 31 Or day < 1 Then
Console.WriteLine("Please enter a valid day")
GoTo retryday
End If
14 ответов
Я собираюсь отличаться от всех остальных и сказать, что сами GOTOs не все зло. Зло происходит от неправильного использования Гото.
В общем, почти всегда есть лучшие решения, чем использование GOTO, но на самом деле бывают случаи, когда GOTO-это правильный способ сделать это.
Я бы написал ваш код вроде этого (мой VB немного ржавый...):
Dim valid As Boolean = False
While Not valid
Console.WriteLine("Please enter the day you were born: ")
Dim day As String
day = Console.ReadLine
If day > 31 Or day < 1 Then
Console.WriteLine("Please enter a valid day.")
Else
valid = True
End If
End While
Если вы возьмете свой код GOTO и посмотрите на него, как кто-то сначала приблизится к вашему коду? "Хм.. retryday? Что это делает? Когда это произойдет? О, так мы получим этот ярлык, если день будет вне диапазона. Хорошо, поэтому мы хотим сделать цикл, пока дата не будет считаться действительной и в диапазоне".
а если вы посмотрите на меня:
http://xkcd.com/292/ я думаю, это стандартное мнение Гото.
вместо этого попробуйте использовать цикл do while. do while петли всегда будут выполняться один раз и велики, когда вам нужно propmt пользователя, но убедитесь, что они вводят правильную информацию.
Sub Main()
Dim valid as Integer
valid=0
Do Until valid = 1
System.Console.WriteLine("enter the day ")
day = System.Console.ReadLine()
If day > 31 Or day < 1 Then
System.Console.WriteLine("Invalid day\n")
valid = 0;
Else
valid = 1
Loop
End Sub
на GOTO
construct производит код sphagetti. Это делает трассировку через код почти невозможной.
процедурное / функциональное программирование-гораздо лучший подход.
вопросы о достоинствах GoTo
заявление (или, скорее, его отсутствие) являются многолетними на этом сайте. Нажмите здесь для примера: - это Гото по-прежнему считаются вредными?
что касается альтернативы GoTo
, в предоставленном фрагменте, a while
loop хорошо бы сделать трюк, может быть, что-то вроде:
day = -1
While (day < 0)
Console.WriteLine("Please enter the day you were born : ")
day = Console.ReadLine
If day > 31 Or day < 1 Then
Console.WriteLine("Please enter a valid day")
day = -1
End If
End While
GOTOs-довольно политическая проблема. "Решение" для GOTOs-использовать другие встроенные навигационные конструкции, такие как функции, методы, циклы и т. д. Для VB вы можете сделать подпроцедуру, которая запускает этот код, или поместить ее в цикл While. Вы можете google обоих этих предметов довольно легко.
немного неуклюжий, но:
Dim bContinue As Boolean
Console.WriteLine("Enter a number between 1 and 31")
Do
Dim number As Integer = Console.ReadLine()
If number >= 1 AndAlso number <= 31 Then
bContinue = True
Else
Console.WriteLine("Please enter a VALID number between 1 and 31")
End If
Loop Until bContinue
также рассмотрим некоторые основные петли в "goto land"
Dim i As Integer
startofloop1:
Debug.WriteLine(i)
i += 1
If i <= 10 Then
GoTo startofloop1
End If
i = 0
startofloop2:
Debug.WriteLine(i * 2)
i += 1
If i <= 10 Then
GoTo startofloop2
End If
вот хороший эквивалент:
For x As Integer = 0 To 10
Debug.WriteLine(i)
Next
For x As Integer = 0 To 10
Debug.WriteLine(i * 2)
Next
что более читаемо и менее подвержено ошибкам?
использование goto считается плохой практикой в течение десятилетий. Возможно, это была обратная реакция на оригинальный BASIC (до Visual Basic). В исходном базовом не было циклов while, локальных переменных (только глобалов), и (в большинстве базовых версий) функции не могли принимать параметры или возвращать значения. Более того, функции не были явно разделены; управление может неявно переходить от одной функции к другой, если вы забыли оператор RETURN. Наконец, отступ кода был иностранным концепция в этих ранних основах.
Если бы вы некоторое время использовали исходный BASIC (как я), вы бы оценили, как использование глобальных переменных и gotos повсюду затрудняет понимание большой программы и без особой осторожности превратили ее в запутанный беспорядок "спагетти". Когда я изучал QBASIC, со своим временем..Я никогда не оглядывался назад.
Я не думаю, что gotos больно в небольших количествах, но в культуре кодера сильное чувство сохраняется что они как-то зло. Поэтому я избегал готос только для того, чтобы не оскорблять чувства. Иногда я нахожу, что goto решает проблему чисто (например, выход из внешнего цикла из внутреннего цикла), но вы должны рассмотреть, делает ли другое решение код более читаемым (например, поместите внешний цикл в отдельную функцию и используйте "функцию выхода" вместо goto во внутреннем цикле).
Я написал программу на C++ с примерно 100 000 строк код и я использовали goto 30 раз. Между тем, существует более 1000 "нормальных" циклов и около 10 000 операторов "if".
функции FTW!
хорошо, я не уверен, что ваш код действительно VB.Net здесь, так как у вас есть некоторые шаткие вещи типа происходит (т. е. Console.Readline
возвращает String
, не число, на котором вы можете делать сравнения)... так что на время забудем о типе.
Console.Writeline("Please enter the day you were born : ")
day = Console.Readline()
While not ValidDate(day)
Console.WriteLine("Please enter a valid day")
day = Console.Readline()
End While
и отдельно
Function ValidDate(day) As Boolean
Return day > 31 Or day < 1
End Function
или вы можете повеселиться с рекурсией и синтаксисом раннего возврата! ;)
Function GetDate() As String
Console.Writeline("Please enter the day you were born : ")
day = Console.Readline()
If ValidDate(day) Then Return day 'Early return
Console.Writeline("Invalid date... try again")
GetDate()
End Function
While True
Console.WriteLine("Please enter the day you were born : ")
day = Console.ReadLine
If day > 31 Or day < 1 Then
Console.WriteLine("Please enter a valid day")
Continue
Else
Break
End If
End While
Вы можете делать почти все, что вы можете сделать с GOTO
s с простыми встроенными языковыми конструкциями, такими как структуры решений и циклы, и GOTO
заявления часто делают для грязного, невозможного для понимания кода спагетти. Петли и ifs и такие имеют четкое, принятое, понятное использование.
см., как обычно предлагается, Dijkstra's Перейти К Заявлению Считается Вредным
Я брошу свой, даже если "по книге" волки здесь будут downvote. Взгляните на : выгодно ли когда-либо использовать "goto" на языке, поддерживающем циклы и функции? Если так, то почему?
Я должен согласиться со всеми здесь: Гото сам по себе не зло, но злоупотребление им, безусловно, сделает вашу жизнь несчастной. Есть так много других структур управления на выбор, и хорошо написанная программа обычно может справиться с большинством ситуаций без goto. Тем не менее, я нахожусь на близкой к завершению точке программы, которая набирает около 15 000 строк, и я использовал один и только один оператор GOTO (который я могу заменить, мы увидим). Это первый раз, когда я использовал GOTO в последних десятках программ, с которыми я имел дело. Но в этом случае он избавился от ошибки компилятора (используя меня.Close () дважды в одном и том же суб, но в разных структурах If; я мог бы подавить его, но я просто бросил ярлык и заменил один меня.Close () with a GoTo CloseLabel). Если я начну работать с большим количеством экземпляров, которые требуют меня.Close () в этой подлодке я, вероятно, поставлю меня.Закройте() в своем собственном sub и просто вызовите этот sub из структур If или других циклов, которые приводят к закрытие программы... Как я уже сказал, есть альтернативы, но иногда, и когда они используются очень редко, экономно и стратегически, GoTo все еще может быть полезен. Просто остерегайтесь кода спагетти, это мигающий беспорядок lol
ваш код в порядке. Он лаконичен и ясен. Это лучше, чем раздувать задание от 50% до 200% С помощью дополнительных переменных и разных глаголов, которые делают то же самое.
Если вы просто перескакиваете назад или вперед к началу или концу логического блока, перейдите(к) для него. "Цикл" или "конец while" по-прежнему является goto, но назначение подразумевается. Единственное преимущество заключается в том, что компилятор не позволит вам сделать два цикла пересекающимися, но он не может с парой gotos. При использовании goto не пересекайте потоки. Это было бы плохо. -- Доктор Шпенглер!--3-->
мой другой питомец peeve является" один вход, один выход " правило. Конечно, у вас может быть только один вход, если вы не пишете в ассемблере. Но правило "одного выхода" глупо. Это просто приводит к куче вложенных проверок границ, которые выводят ваш код с правого края. Гораздо яснее проверить все ваши параметры в верхней части рутины и" выйти из суб", если они незаконны. Что делает больше смысл?
if badparam then
log error
exit sub
endif
if badparam2 then
log error2
exit sub
endif
do stuff
или это?
if goodparam then
if goodparam2 then
do stuff
else
log error2
endif
else
log error
endif
когда у вас есть шесть проверок границ и "материал" - это 60 строк, которые вы не можете разбить на меньшие биты, тогда второй способ превращается в кошмар для тех, кто должен его поддерживать. Лучше закончить то, что вы делали-проверку исключений-чем откладывать всю обработку исключений до конца.
мои 0.02$