Операторы перехода и альтернативы в VB.NET

Я отправил фрагмент кода на другом обращающемся за помощью форуме и люди, на которых указывают мне то использование GoTo операторы являются очень плохой практикой программирования. Я задаюсь вопросом: почему это плохо?

Какие альтернативы GoTo там должны использовать в VB.NET, который обычно считали бы большим количеством лучшей практики?

Рассмотрите этот отрывок ниже, где пользователь должен ввести их дату рождения. Если бы месяц/дата/год недопустим или нереалистичен, я хотел бы циклично выполниться назад и спросить пользователя снова. (Я использую, если операторы для проверки размера целого числа..., если бы существует лучший способ сделать это, я ценил бы, если Вы могли бы сказать мне это также :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
9
задан Harry Johnston 25 September 2012 в 23:14
поделиться

11 ответов

Я собираюсь отличаться от всех остальных и сказать, что ГОТО сами по себе не все зло. Зло исходит от неправильного использования GOTO.

В общем, почти всегда есть лучшие решения, чем использование GOTO, но действительно бывают случаи, когда 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? Что это делает? Когда это происходит? О, значит, мы переходим к этой метке, если день выходит за пределы допустимого диапазона. Хорошо, поэтому мы хотим выполнить цикл до тех пор, пока дата не будет считаться действительной и находящейся в диапазоне» .

Если вы посмотрите на мой:

«О, мы хотим продолжать делать это до тех пор, пока он не станет действительным. Это действительно, когда дата находится в пределах диапазона».

18
ответ дан 4 December 2019 в 07:22
поделиться

Часто рекомендуется следовать совету Дейкстры в «Заявлении о вреде».

Дональд Кнут довольно солидно ответил Дейкстре. Этот пример является современной версией одного из его контрпримеров. Лично я пишу бесконечные циклы с внутренними перерывами, когда сталкиваюсь с этим, но есть несколько других редких случаев, когда я буду писать операторы GOTO.

Наиболее распространенными для меня являются выход из глубоко вложенных циклов и такой шаблон:

ContinueTry:
   Try
        'Worker code
   Catch ex as IO.IOException
        If MessageBox.Show(...) = DialogResult.Retry Then Goto ContinueTry
        Throw
   End Try

У меня также есть два случая больших конечных автоматов с операторами goto, обеспечивающими переходы.

0
ответ дан 4 December 2019 в 07:22
поделиться

Вопросы о достоинствах заявления GoTo (или, скорее, об отсутствии такового) на этом сайте постоянно возникают. Щелкните здесь, чтобы увидеть пример: GoTo по-прежнему считается вредным?

Что касается альтернативы GoTo , в предоставленном фрагменте кода цикл while отлично подойдет для трюк, может быть что-то вроде:

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
2
ответ дан 4 December 2019 в 07:22
поделиться

http://xkcd.com/292/ {{1} } Я думаю, что это стандартное мнение Гото.

вместо этого попробуйте использовать цикл do while. Циклы do while всегда выполняются один раз и отлично подходят, когда вам нужно поддерживать пользователя, но убедитесь, что они вводят правильную информацию.

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
6
ответ дан 4 December 2019 в 07:22
поделиться

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

См., Как обычно предлагают, Заявление Дейкстры о переходе к делу, признанное вредным

0
ответ дан 4 December 2019 в 07:22
поделиться

Ваш код в порядке. Это лаконично и понятно. Это лучше, чем раздувать работу на 50–200% дополнительными переменными и разными глаголами, которые делают то же самое.

Если вы просто переходите назад или вперед к началу или концу логического блока, тогда перейдите (к) для этого. «Цикл» или «Конец в то время» по-прежнему остается переходом, но подразумевается пункт назначения. Единственное преимущество состоит в том, что компилятор не позволит вам создать перекрестные пути двух циклов, но не с парой goto. При использовании goto не пересекайте потоки. Это было бы плохо. - Доктор Шпенглер

Другая моя любимая мозоль - это правило «один вход, один выход». Конечно, у вас может быть только один вход, если вы не пишете на ассемблере. Но правило «одного выхода» глупо. Это просто приводит к набору вложенных проверок границ, которые уводят ваш код за пределы правого поля. Гораздо понятнее проверить все ваши параметры в верхней части подпрограммы и «выход из подпрограммы», если они недопустимы. Что имеет больше смысла?

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 доллара

-2
ответ дан 4 December 2019 в 07:22
поделиться
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
0
ответ дан 4 December 2019 в 07:22
поделиться

Использование goto уже несколько десятилетий считается плохой практикой. Возможно, это была негативная реакция на исходный BASIC (до Visual Basic). В исходном BASIC не было циклов while, локальных переменных (только глобальные) и (в большинстве версий BASIC) функции не могли принимать параметры или возвращать значения. Более того, функции не были явно разделены; управление может неявно переходить от одной функции к другой, если вы забыли оператор RETURN. Наконец, отступы в коде были чужеродным понятием для этих ранних BASIC.

Если вы какое-то время использовали исходный BASIC (как я), вы бы оценили, как повсеместное использование глобальных переменных и gotos делает большую программу трудной для понимания и без особой осторожности превращает ее в запутанная каша из «спагетти». Когда я изучил QBASIC с его циклами WHILE..WEND и SUB, я никогда не оглядывался назад.

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

Я написал программу на C ++ примерно с 100 000 строк кода и 30 раз использовал goto. Между тем, существует более 1000 «нормальных» циклов и около 10 000 «если» операторов.

1
ответ дан 4 December 2019 в 07:22
поделиться

Немного неуклюже, но:

    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

Какой из них более читаем и менее подвержен ошибкам?

1
ответ дан 4 December 2019 в 07:22
поделиться

Конструкция GOTO создает код сфагетти. Это делает практически невозможным отслеживание кода.

Процедурное / функциональное программирование - гораздо лучший подход.

2
ответ дан 4 December 2019 в 07:22
поделиться

GOTO - это довольно политический вопрос. «Решение» для GOTO - использовать другие встроенные конструкции навигации, такие как функции, методы, циклы и т. Д. Для VB вы можете создать подпроцедуру, которая запускает этот код, или поместить ее в цикл While. Вы можете довольно легко погуглить обе эти темы.

1
ответ дан 4 December 2019 в 07:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: