VB.NET 中的 GoTo 语句和替代语句

发布于 2024-08-30 13:11:45 字数 509 浏览 13 评论 0原文

我在另一个论坛上发布了一个代码片段寻求帮助,人们向我指出使用 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

I've posted a code snippet on another forum asking for help and people pointed out to me that using GoTo statements is very bad programming practice. I'm wondering: why is it bad?

What alternatives to GoTo are there to use in VB.NET that would be considered generally more of a better practice?

Consider this snippet below where the user has to input their date of birth. If the month/date/year are invalid or unrealistic, I'd like to loop back and ask the user again. (I'm using if statements to check the integer's size... if there's a better way to do this, I'd appreciate if you could tell me that also :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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

老旧海报 2024-09-06 13:11:45

我要与其他人不同的是,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 代码看一下,别人会如何首先处理你的代码? “嗯..重试日?这有什么作用?什么时候发生?哦,所以如果日期超出范围,我们就转到该标签。好的,所以我们要循环,直到日期被认为是有效且在范围内” 。

而如果你看我的:

“哦,我们想继续这样做,直到它有效。当日期在范围内时它是有效的。”

I'm going to differ from everyone else and say that GOTOs themselves are not all the evil. The evil comes from the misuse of GOTO.

In general, there is almost always better solutions than using a GOTO, but there really are times when GOTO is the proper way to do it.

That being said, you are a beginner, so you shouldn't be allowed to judge if GOTO is proper or not (because it hardly ever is) for a few more years.

I would write your code like this (my VB is a bit rusty...):

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

If you take your GOTO code and look at it, how would someone first approach your code? "Hmm.. retryday? What does this do? When does this happen? Oh, so we goto that label if the day is out of range. Ok, so we want to loop until the date is considered to be valid and in range".

Whereas if you look at mine:

"Oh, we want to keep doing this until it's Valid. It is valid when the date is within range."

南七夏 2024-09-06 13:11:45

http://xkcd.com/292/ 我认为这是GoTo<的标准意见/代码>。

相反,尝试使用 Do Until 循环。 Do Until 循环将始终执行一次,当您需要提示用户并希望确保在他们输入正确的信息之前不会继续操作时,它非常有用。

Sub Main()
    'Every time the loop runs, this variable will tell whether
    'the user has finally entered a proper value.
    Dim Valid As Boolean = False

    'This is the variable which stores the final number which user enters.
    Dim Day As Integer = 0
    Do Until Valid
        Console.WriteLine("Enter the day:")
        Dim DayStr As String = Console.ReadLine()

        If Not Integer.TryParse(DayStr, Day) Then
            Console.WriteLine("Invalid value! It must be a valid number.")
            Valid = False
        ElseIf (Day < 1) Or (Day > 31) Then
            onsole.WriteLine("Invalid day! It must be from 1 to 31.")
           Valid = False
        Else
           Valid = True
        End If
    Loop

    'blablabla
    'Do whatever you want, with the Day variable
End Sub

http://xkcd.com/292/ I think this is the standard opinion of GoTo.

Instead, try and use a Do Until loop. Do Until loops will always execute once and are great when you need to prompt the user and want to make sure that you do not proceed until they enter the correct information.

Sub Main()
    'Every time the loop runs, this variable will tell whether
    'the user has finally entered a proper value.
    Dim Valid As Boolean = False

    'This is the variable which stores the final number which user enters.
    Dim Day As Integer = 0
    Do Until Valid
        Console.WriteLine("Enter the day:")
        Dim DayStr As String = Console.ReadLine()

        If Not Integer.TryParse(DayStr, Day) Then
            Console.WriteLine("Invalid value! It must be a valid number.")
            Valid = False
        ElseIf (Day < 1) Or (Day > 31) Then
            onsole.WriteLine("Invalid day! It must be from 1 to 31.")
           Valid = False
        Else
           Valid = True
        End If
    Loop

    'blablabla
    'Do whatever you want, with the Day variable
End Sub
走走停停 2024-09-06 13:11:45

GOTO 构造生成 sphagetti 代码。这使得通过代码进行跟踪几乎是不可能的。

过程式/函数式编程是一种更好的方法。

The GOTO construct produces sphagetti code. This makes tracing through code almost impossible.

Procedural / Functional programming is a much better approach.

猫卆 2024-09-06 13:11:45

关于 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

Questions about the merits of the GoTo statement (or rather the lack thereof) are perennial on this site. Click here for an example: Is GoTo still considered harmful?

With regards to an alternative to GoTo, in the provided snippet, a while loop would nicely do the trick, maybe something like:

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
浊酒尽余欢 2024-09-06 13:11:45

GOTO 是一个相当政治的问题。 GOTO 的“解决方案”是使用其他内置导航结构,如函数、方法、循环等。对于 VB,您可以创建一个运行该代码的子过程,或者将其放入 While 循环中。你可以很容易地用谷歌搜索这两个主题。

GOTOs are a pretty political issue. The 'solution' to GOTOs is to use other built-in navigation constructs like functions, methods, loops, etc. For VB, you could make a sub-procedure that runs that code, or put it in a While loop. You can google both of those subjects fairly easily.

抚你发端 2024-09-06 13:11:45

有点笨拙,但是:

    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

哪个更具可读性并且更不容易出错?

A little clunky but:

    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

Also consider some basic loops in "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

Here's the nice equivalent:

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

Which is more readable and less error prone?

白云悠悠 2024-09-06 13:11:45

几十年来,使用 goto 一直被认为是一种不好的做法。也许这是对最初的 BASIC(在 Visual Basic 之前)的强烈反对。在最初的 BASIC 中,没有 while 循环,没有局部变量(只有全局变量),并且(在大多数 BASIC 版本中)函数不能接受参数或返回值。此外,功能没有明确分离;如果您忘记了 RETURN 语句,控制权可能会隐式地从一个函数转移到另一个函数。最后,代码缩进在这些早期的 BASIC 中是一个外国概念。

如果你使用最初的 BASIC 一段时间(就像我一样),你会意识到全局变量和 goto 的使用无处不在使得一个大程序变得难以理解,而且一不小心就把它变成了一堆混乱的东西。 “意大利细面条”。当我学习 QBASIC 及其 WHILE..WEND 循环和 SUB 时,我从未回头。

我不认为 goto 的伤害很小,但在编码器文化中,一种强烈的感觉挥之不去,认为它们在某种程度上是邪恶的。因此,我会避免使用 goto,无非是为了避免冒犯别人的感受。有时我发现 goto 可以干净地解决问题(例如从内循环中跳出外循环),但您应该考虑其他解决方案是否使代码更具可读性(例如,将外循环放在单独的函数中并使用“ exit 函数”,而不是内部循环中的 goto)。

我编写了一个 C++ 程序,大约有 100,000 行代码,并且使用了 30 次 goto。同时,有超过 1,000 个“正常”循环和大约 10,000 个“if”语句。

Using goto has been considered a bad practice for decades now. Perhaps it was a backlash against the original BASIC (before Visual Basic). In the original BASIC there were no while loops, no local variables (only globals), and (in most BASIC versions) functions could not take parameters or return values. Moreover, functions were not explicitly separated; control can implicitly fell from one function to another if you forgot a RETURN statement. Finally, code indentation was a foreign concept in these early BASICs.

If you used the original BASIC for a some time (like I did), you would come to appreciate how the use of global variables and gotos everywhere makes a large program hard to understand, and without great care, turned it into a tangled mess of "spaghetti". When I learned QBASIC, with its WHILE..WEND loops and SUBs, I never looked back.

I don't think gotos hurt in small quantities, but in the coder culture a strong sense lingers that they are somehow evil. Therefore, I would avoid gotos for no other reason than to avoid offending sensibilities. Occasionally I find that a goto solves a problem cleanly (like breaking out of an outer loop from within an inner loop), but you should consider whether another solution makes the code more readable (e.g. put the outer loop in a separate function and use "exit function", instead of goto, in the inner loop).

I wrote a C++ program with perhaps 100,000 lines of code and I've used goto 30 times. Meanwhile, there are more than 1,000 "normal" loops and around 10,000 "if" statements.

一生独一 2024-09-06 13:11:45

功能 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

Functions FTW!

Okay, I'm not sure if your code is really VB.Net here, since you've got some wonky type stuff going on (i.e. Console.Readline returns a String, not a number you can do comparisons on)... so we'll just forget about type for the moment.

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

And separately

Function ValidDate(day) As Boolean
  Return day > 31 Or day < 1
End Function

Or you could have fun with recursion and early-return syntax! ;)

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
无风消散 2024-09-06 13:11:45
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
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
雄赳赳气昂昂 2024-09-06 13:11:45

您可以使用简单的内置语言结构(例如决策结构和循环)来完成使用 GOTO 可以做的几乎任何事情,而 GOTO 语句通常会造成混乱且无法完成的任务。 -理解意大利面条代码。循环和 if 等具有清晰、可接受、易于理解的用法。

正如通常建议的那样,请参阅 Dijkstra 的被视为有害的转到声明

You can do almost anything that you can do with GOTOs with simple built-in language constructs like decision structures and loops, and GOTO statements often make for messy, impossible-to-understand spaghetti code. Loops and ifs and such have a clear, accepted, understandable usage.

See, as is usually suggested, Dijkstra's Go-To Statement Considered Harmful

-小熊_ 2024-09-06 13:11:45

通常建议我们遵循 Dijkstra 在《被认为有害的首选声明》中的建议。

唐纳德·高德纳 (Donald Knuth) 对迪杰斯特拉 (Dijkstra) 的回答非常中肯。这里的这个例子是他的一个反例的现代版本。就我个人而言,当我遇到这种情况时,我会编写带有内部中断的无限循环,但在其他一些罕见的情况下,我会编写 GOTO 语句。

对我来说最常见的是打破深层嵌套循环和这种模式:

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

我还有两种大型有限状态机的情况,其中 goto 语句提供转换。

It is often recommended that we follow Dijkstra's advice in Go-To Statement Considered Harmful.

Donald Knuth answered Dijkstra pretty soundly. This example here is a modern version of one of his counterexamples. Personally I write infinite loops with internal breaks when I encounter this one but there's a few other rare cases where I will write GOTO statements.

The most common ones for me are breaking out of deeply nested loops and this pattern:

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

I also have two cases of large finite state machines with goto statements providing the transitions.

冰魂雪魄 2024-09-06 13:11:45

即使外面的“按规矩”狼群会投反对票,我也会投我的票。
看看:在支持循环和函数的语言中使用“goto”是否有利?如果是这样,为什么?

I'll throw mine even though the 'by the book' wolves outhere will downvote.
Have a look at : Is it ever advantageous to use 'goto' in a language that supports loops and functions? If so, why?

失与倦" 2024-09-06 13:11:45

我必须同意这里其他人的观点:GOTO 本身并不邪恶,但滥用它肯定会让你的生活变得悲惨。还有许多其他控制结构可供选择,编写良好的程序通常可以处理大多数情况而无需 goto。话虽如此,我的程序已接近完成,该程序约有 15,000 行,我使用了一个且仅一个 GOTO 语句(我们可能会替换它)。在我处理过的十多个程序中,这是我第一次使用 GOTO。但在这种情况下,它消除了编译器错误(在同一个 Sub 中但在不同的 If 结构中使用 Me.Close() 两次;我本可以抑制它,但我只是简单地放入一个标签并将一个 Me.Close() 替换为转到关闭标签)。如果我开始遇到更多需要在此子中使用 Me.Close() 的实例,我可能会将 Me.Close() 放入其自己的子中,然后简单地从 If 结构或其他导致关闭的循环中调用该子程序的... 正如我所说,还有其他选择,但有时,当很少、谨慎且有策略地使用时,GoTo 仍然会有所帮助。只是要小心意大利面条代码,那是一团混乱,哈哈

I've got to agree with everyone else here: GOTO itself is not evil, but misusing it will certainly make your life miserable. There are so many other control structures to choose from, and a well-written program can usually handle most every situation without goto. That being said, I am at the near-completion point of a program that's racking up about 15,000 lines, and I used one, and only one, GOTO statement (which I may be replacing we will see). It's the first time I've used GOTO in the last dozen or so programs I've dealt with. But in this instance it got rid of a compiler error (using Me.Close() twice within the same Sub but within different If structures; I could have suppressed it but I simply threw in a label and replaced one Me.Close() with a GoTo CloseLabel). If I start running into more instances that require Me.Close() within this Sub, I'm likely to put Me.Close() in its own sub and simply call that sub from the If structures or other loops that result in a closing of the program... As I said, there's alternatives, but sometimes, and when used very rarely, sparingly, and strategically, GoTo can still be helpful. Just beware of spaghetti code, that's a blinking mess lol

最丧也最甜 2024-09-06 13:11:45

你的代码没问题。它简洁明了。这比用额外的变量和做同样事情的不同动词将工作膨胀 50% 到 200% 更好。

如果您只是向后或向前跳到逻辑块的开头或结尾,那么 go(to) 即可。 “循环”或“结束同时”仍然是一个跳转,但目的地是隐含的。唯一的优点是编译器将阻止您使两个循环交叉路径,但它不能使用一对 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 美元

Your code is fine. It is concise and clear. It is better than inflating the job 50% to 200% with extra variables and different verbs that do the same thing.

If you are just skipping backwards or forwards to the beginning or end of a logical block, then go(to) for it. A "Loop" or an "End while" is still a goto, but the destination is implied. The only advantage is that the compiler will stop you from making two loops cross paths, but it can't with a pair of gotos. When using goto's, don't cross the streams. That would be bad. -- Dr. Spengler

My other pet peeve is the "one entrance, one exit" rule. Of course you can only have one entrance, unless you are writing in assembler. But the "one exit" rule is stupid. It just leads to a bunch of nested bounds checks that walks your code off the right margin. It is much more clear to test all your parameters at the top of the routine and "exit sub" if they are illegal. What makes more sense?

if badparam then
  log error
  exit sub
  endif

if badparam2 then
  log error2
  exit sub
  endif

do stuff

or this?

if goodparam then
  if goodparam2 then
    do stuff
  else
    log error2
    endif
else
  log error 
  endif 

When you have six bounds checks and "stuff" is 60 lines that you can't break up into smaller bits, then the second way turns into a nightmare for anyone who has to maintain it. It's better to finish what you were doing -- checking the exceptions -- than to defer all the exception handling to the end.

My $0.02

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文