web-dev-qa-db-ja.com

VB.NETのGoToステートメントと代替

私は別のフォーラムにコードスニペットを投稿して助けを求めましたが、GoToステートメントを使用することは非常に悪いプログラミング慣行であると人々が指摘しました。私は疑問に思っています:なぜそれは悪いのですか?

VB.NETで使用するGoToの代替手段はありますか?一般的にはより良い方法と見なされますか?

ユーザーが生年月日を入力する必要がある以下のスニペットについて考えてみます。月/日付/年が無効または非現実的である場合は、ループバックしてユーザーにもう一度質問したいと思います。 (私は整数のサイズをチェックするために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
9
qais

私は他の人とは異なり、GOTO自体がすべての悪ではないということを言います。悪は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
Earlz

http://xkcd.com/292/ これは後藤の標準的な意見だと思います。

代わりに、dowhileループを試して使用してください。 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
Andy

GOTOコンストラクトは、スパゲッティコードを生成します。これにより、コードをトレースすることはほとんど不可能になります。

手続き型/関数型プログラミングは、はるかに優れたアプローチです。

2
Raj More

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
mjv

GOTOはかなり政治的な問題です。 GOTOの「解決策」は、関数、メソッド、ループなどの他の組み込みナビゲーション構造を使用することです。VBの場合、そのコードを実行するサブプロシージャを作成するか、Whileループに入れることができます。あなたはそれらの主題の両方をかなり簡単にグーグルで検索することができます。

1
brydgesk

少し不格好ですが:

    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

「gotoland」のいくつかの基本的なループも考慮してください

        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

これがNiceの同等物です:

   For x As Integer = 0 To 10
        Debug.WriteLine(i)
    Next
    For x As Integer = 0 To 10
        Debug.WriteLine(i * 2)
    Next

どちらが読みやすく、エラーが発生しにくいですか?

1
Jeremy

Gotoの使用は、何十年もの間悪い習慣と見なされてきました。おそらく、それは元のBASIC(Visual Basicより前)に対する反発でした。元のBASICには、whileループ、ローカル変数(グローバルのみ)、および(ほとんどのBASICバージョンでは)関数がパラメーターを受け取ったり値を返したりすることができませんでした。さらに、機能は明示的に分離されていませんでした。 RETURNステートメントを忘れた場合、制御は暗黙的に1つの関数から別の関数に落ちる可能性があります。最後に、コードのインデントは、これらの初期のBASICでは異質な概念でした。

元のBASICをしばらく使用した場合(私が行ったように)、グローバル変数とgotoをどこでも使用すると、大規模なプログラムが理解しにくくなり、細心の注意を払わずに、複雑な混乱に変わったことに気付くでしょう。 "スパゲッティ"。 WHILE..WENDループとSUBを備えたQBASICを学んだとき、私は決して振り返りませんでした。

ゴトが少しでも傷つくとは思いませんが、コーダー文化では、ゴトはどういうわけか邪悪であるという強い感覚が残っています。したがって、私は不快な感性を避ける以外の理由でゴトスを避けます。ときどき、gotoが問題をきれいに解決することがあります(内側のループ内から外側のループを抜け出すなど)が、別の解決策でコードが読みやすくなるかどうかを検討する必要があります(たとえば、外側のループを別の関数に入れて「内側のループで、gotoの代わりに「exitfunction」)。

私はおそらく100,000行のコードでC++プログラムを作成し、gotoを30回使用しました。一方、1,000を超える「通常の」ループと約10,000の「if」ステートメントがあります。

1
Qwertie

機能FTW!

さて、ここであなたのコードが本当にVB.Netであるかどうかはわかりません。なぜなら、いくつかの奇妙なタイプのものが進行しているからです(つまり、Console.ReadlineStringを返しますが、比較できる数値ではありません)...なので、今のところタイプについては忘れてしまいます。

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
1
Jeff Bridgman
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
Andrey

決定構造やループなどの単純な組み込み言語構造を使用して、GOTOsで実行できるほとんどすべてのことを実行できます。また、GOTOステートメントは、多くの場合、厄介で理解できないスパゲッティコードになります。ループやifなどには、明確で、受け入れられ、理解できる使用法があります。

通常提案されているように、ダイクストラの 有害と見なされるGo-Toステートメント を参照してください。

0
froadie

私はここにいる他のみんなに同意しなければなりません:GOTO自体は悪ではありませんが、それを誤用すると確かにあなたの人生は悲惨になります。選択できる制御構造は他にもたくさんあり、適切に作成されたプログラムは通常、gotoなしでほとんどすべての状況を処理できます。そうは言っても、私は約15,000行を積み上げるプログラムの完了間近の段階にあり、GOTOステートメントを1つだけ使用しました(これは後で置き換える可能性があります)。私が扱った過去12ほどのプログラムでGOTOを使用したのはこれが初めてです。しかし、この例では、コンパイラエラーを取り除きました(同じSub内で異なるIf構造内でMe.Close()を2回使用しました。抑制できたはずですが、ラベルを挿入して1つのMe.Close()を次のように置き換えました。 GoTo CloseLabel)。このSub内でMe.Close()を必要とするインスタンスがさらに発生し始めた場合、Me.Close()を独自のサブに配置し、If構造または他のループからそのサブを呼び出すだけで終了する可能性があります。プログラムの...私が言ったように、代替手段がありますが、時々、そして非常にまれに、控えめに、そして戦略的に使用されるとき、GoToはまだ役に立ちます。スパゲッティコードに注意してください、それはまばたきの混乱です笑

0
Michael Tant

有害と見なされるGo-Toステートメントのダイクストラのアドバイスに従うことがしばしば推奨されます。

ドナルド・クヌースはダイクストラにかなりしっかりと答えました。この例は、彼の反例の1つの最新バージョンです。個人的には、これに遭遇したときに内部ブレークを含む無限ループを作成しますが、GOTOステートメントを作成するまれなケースが他にもいくつかあります。

私にとって最も一般的なものは、深くネストされたループとこのパターンから抜け出すことです。

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

また、遷移を提供するgotoステートメントを持つ大規模な有限状態マシンの2つのケースがあります。

0
Joshua

「本による」オオカミが反対票を投じても、私は私のものを投げます。見てください: ループと関数をサポートする言語で「goto」を使用することはこれまでに有利ですか?もしそうなら、なぜですか?

0
lauCosma