【问题标题】:C# goto use - what else to use here?C# goto use - 这里还有什么要使用的?
【发布时间】:2010-09-24 09:03:07
【问题描述】:

我知道大多数人都说要避免使用 goto,但是我在很多地方读到过,如果您需要简单的代码,有时它会很有用。 目前我有一个非常简单的程序,如果用户选择,则需要重复:

static void Main()
{
    Restart:
    ...

    string UserChoice=Console.ReadLine();
    if (UserChoice=="y")
    goto Restart;
}

在这里使用 goto 真的很糟糕吗?我只是看不到任何其他方式如何在不执行循环等的情况下重复代码。这似乎是一种非常简单明了的方式。还是我错过了什么?

【问题讨论】:

  • 循环有什么问题?
  • 循环没有问题,我只是在问。
  • 无论如何,现在你有other things to worry aboutSCNR
  • 回复:XKCD 草图,这应该真的发生了!

标签: c# syntax goto


【解决方案1】:
string userchoice;

do {                

    userchoice=Console.ReadLine();

} while (userchoice=="y");

【讨论】:

    【解决方案2】:

    改为写下类似的内容。

    while(Console.ReadLine() == "y")
    {
    .....
    }
    

    是的,使用 goto 很糟糕,因为它会降低代码的可读性。

    【讨论】:

    • 根据他的例子,他似乎想在 Console.ReadLine 之前做一些逻辑,所以这不会和他当前的代码完全一样,因为它首先从控制台读取,然后执行逻辑.
    • 如果是这种情况,请执行 { ... } while(Console.ReadLine() == "y") 将起作用。
    • 同意。我认为这是最干净的方式。好答案!
    【解决方案3】:

    当然,如果您的代码要一次又一次地做同样的事情,您必须添加一个循环。这比 goto 好多了。

    使用类似的东西

    string UserChoice = "y";
    while( UserChoice == "y"){
      ...
      UserChoice=Console.ReadLine();
    }
    

    这对你应该很有效。

    【讨论】:

    • -,您在这里遇到了一些逻辑错误:它应该在用户不输入“y”时循环,这是错误的 - 它应该在用户输入“y”时循环
    • @Andreas:谢谢。现在修好了。我猜转到我的头;)
    • 这与海报逻辑不符。循环条件也总是假的。
    • 我知道 :) ...但是这些点可以代表一个方法调用,可以在 while 之前插入 ... 看,50/50 ...
    • @Andreas 不,我的意思是它永远不会运行任何东西,因为 UserChoice 初始化错误。
    【解决方案4】:

    在这里使用 goto 真的很糟糕吗?

    1968 年 3 月,DijkstraCommunications of the ACM 发了一封信,以Go To Statement Considered Harmful 为标题发表。这是一本有趣的读物,也是程序员知识的一部分。

    这封信中提出的反对 GOTO 的论点与程序员如何构建心智模型来跟踪代码执行进度有关。 Dijkstra 认为这种心智模型很重要,因为变量的值仅相对于执行进度才有意义。例如,当我们的程序计算一个事件发生的次数时,总会有一个中间时刻发生了 N 个事件,但跟踪它的变量还没有增加,仍然是 N-1。

    他在反对 GOTO 的推理中经历了这些步骤:

    1. 首先考虑一种没有过程、循环或 GOTO 的非常简单的语言。在这样的语言中,程序员可以通过想象一个从文件开头到结尾的执行指针来在心理上跟踪执行。单个索引(即行号)足以对执行进度进行建模。

    2. 现在我们将过程添加到语言中。执行进度不能再由单个索引跟踪,因为它可能在一个过程中。我们还必须跟踪该过程是从哪一行调用的。此外,可以从其他过程调用过程。因此,我们将执行进度建模为一系列索引。 (在现实生活中,程序员将这样的序列称为“堆栈跟踪”。)

    3. 现在我们为语言添加循环。对于循环体中的堆栈跟踪中的每一行,我们需要添加另一种类型的索引来模拟执行进度:重复计数。

    4. 现在我们添加 GOTO。 Dijkstra 认为,如果肆无忌惮地使用 GOTO,我们现在跟踪执行进度的能力就会崩溃。我们仍然可以通过说“现在我们正在执行第 152 条语句”来使用“执行时钟”跟踪执行进度。但是,这对于建立解释变量值所必需的上下文并没有真正的帮助。

    只要我们只使用 GOTO 语句来构建简单的循环,你可以认为情况等同于第 (3) 点,没有问题。但在这种情况下,您可以只使用循环结构。最好将 GOTO 排除在您的代码之外,这样您就不会陷入第 (4) 点中描述的情况。

    【讨论】:

    • 我要补充一点,在自动生成的机器使用代码中,goto 通常被认为是可以接受的。事实上,对于自动生成的状态机,它们可能是唯一明智的选择。
    【解决方案5】:

    我会使用 do/while 循环:

    string UserChoice = "";
    do {
        ...
        UserChoice=Console.ReadLine();
    } while(UserChoice == "y");
    

    【讨论】:

    • 删除了反对票,由于 halfdan 的更正...顺便说一句:为什么所有的人都使用 "" ... :)
    • @Andreas 在快速回答时可能会导致打字速度更快
    • @Andreas 也许他有.Net 2? ;)
    【解决方案6】:

    答案中缺少一个基本解决方案,

    while (true)
    {
        ...
        if (other-stop-condition) break;     
    
        ...
    
        string UserChoice=Console.ReadLine();
        if (UserChoice != "y") break;
    }
    

    break 语句被认为比纯 while 结构更少,但比(真正的)goto 更有结构。它应该谨慎使用,但它的用途类似于other-stop-condition

    在这里使用 goto 真的很糟糕吗?

    不在这个简单的程序中。但是,如果您继续使用goto 来替换循环、if/then 等,那么您的代码的复杂性将比避免使用goto 的代码增加得快得多。

    【讨论】:

    • 您将 goto 替换为 break ,这只是另一种类型的 goto,虽然不那么冒犯;)
    • @Bear Monkey:对了,我忘记了一些评论。
    • 我确定你知道这一点。有时人们随意使用 break、continue 和 return 语句,但随后对 goto 感到恐惧,却没有意识到这些控制语句流可能与 goto 一样糟糕。
    【解决方案7】:

    您可以使用递归函数来执行相同的操作,而无需循环:

    public static void Main(string[] args)
    {
       PrintChoices();
    }
    
    private static void PrintChoices()
    {
        string userChoice = Console.ReadLine();
    
        if (userChoice == "y")
            PrintChoices();        
    }
    

    【讨论】:

    • 您可能(在极端情况下)遇到“递归太深”的问题,这是您在循环情况下没有的。
    • 当然,我建议一如既往地在生产代码中添加限制以避免递归深度限制问题。另外,我更喜欢循环选项,但他要求在不使用循环的情况下做同样的事情。
    【解决方案8】:

    使用方法而不是 GOTO 被更广泛地接受:

    static void Main()
    {
        Restart();
    }
    
    static void Restart()
    {
        ...code
    
        string userChoice = Console.ReadLine();
        if (userChoice=="y")
            Restart();
    }
    

    【讨论】:

    • C# 还没有针对尾递归进行优化(如果我错了,请纠正我),所以这会增加你的调用堆栈。如果这是用户控制的(如您的示例),可能不是问题,但请考虑您是否运行 Restart() 数千次。堆栈溢出,你好?
    • 不难检查是否实现了尾调用 ildasm 并检查 msdn.microsoft.com/en-us/library/…
    • 这是一个有趣的观点@Zano,但 15000 次用户交互似乎有点不太可能(对于控制台应用程序)。
    • ^ 应该是 1500,显然这取决于 Restart() 中有多少代码
    【解决方案9】:

    使用 do while 循环替换您的 goto,使其更具可读性。

    do 
    {
    ...
    }
    while(Console.ReadLine() == "y");
    

    【讨论】:

      【解决方案10】:

      就我个人而言,我从来没有使用过 goto,就像 Øyvind Bråthen 和 Numenor 所说的那样,循环方法是迄今为止完成这项任务的最佳方式。

      但是,有一种情况我可以想到 goto 会有帮助的地方

      在 C# 中,开关“失败”是非法的(导致编译器错误):

      switch (a) 
      { 
          case 3: 
              b = 7; 
          case 4: 
              c = 3; 
              break; 
          default: 
              b = 2; 
              c = 4; 
              break; 
      }
      

      要让它工作,你可以使用 goto:

      switch (a) 
      { 
          case 3: 
              b = 7;
              goto case 4;
          case 4: 
              c = 3; 
              break; 
          default: 
              b = 2; 
              c = 4; 
              break; 
      }
      

      【讨论】:

      • -,与问题的关系??
      • 该死的...阅读问题:Is using goto here really so bad? I just cannot see any other way how to repeat the code without doing loops etc....您的答案如何捕获循环?所以应该是评论
      • 再一次重复我自己:您的回答提供了有关goto 的更多信息,但没有问到这...问题是:Is using goto **here** really so bad? I just cannot see any other way how to repeat the code without doing loops etc. ...您跑题了!
      • 你争论的越多,你就越同意我的反对和反对:) 你的回答应该是一个简单的评论,他们是为了什么
      • @jimplode:我真的很喜欢你的回答。在用 C++ 编码多年后,我最近才开始用 C# 编码,我很惊讶 C# 不允许 switch case 失败,因为它们有时非常漂亮和有用。我喜欢你的工作。
      【解决方案11】:
      class Program
      {
          static void Main(string[] args)
          {
              int add;
              try
              {
                  ArrayList al = new ArrayList();
              t:
                  Console.Write("Enter the Number of elements do you want to insert in arraylist");
                  int n = Convert.ToInt32(Console.ReadLine());
                  Console.WriteLine("Enter the Values:");
                  for (int i = 0; i < n; i++)
                  {
                      al.Add(Console.ReadLine());
      
                  }
                  foreach (var a in al)
                  {
                      Console.WriteLine("valus:" + a);
                  }
                  Console.WriteLine("Add another number yes:1 ");
                  add = Convert.ToInt32(Console.ReadLine());
                  while (add == 1)
                  {
                      goto t;
      
                  }
              }
              catch (Exception ex)
              {
                  Console.WriteLine("Enter the Valid Number and try again");
              }
              Console.ReadKey();
      
      
          }
      }
      

      }

      【讨论】:

      • 此代码是根据用户要求在 c# 控制台应用程序中使用动态 Arraylist 插入元素的 Goto 语句
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-03
      • 1970-01-01
      相关资源
      最近更新 更多