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

Вы можете делать почти все, что вы можете сделать с GOTOs с простыми встроенными языковыми конструкциями, такими как структуры решений и циклы, и GOTO заявления часто делают для грязного, невозможного для понимания кода спагетти. Петли и ifs и такие имеют четкое, принятое, понятное использование.

см., как обычно предлагается, Dijkstra's Перейти К Заявлению Считается Вредным


часто рекомендуется следовать совету Дийкстры в заявлении Go-To, которое считается вредным.


Я брошу свой, даже если "по книге" волки здесь будут 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$