C#中类似于Java的continue <label>的语法是什么?

35

应该很简单快捷:我想要一个C#版本的以下Java代码的等效版本:

应该很简单快捷:我想要一个C#版本的以下Java代码的等效版本:

orig: for(String a : foo) {
  for (String b : bar) {
    if (b.equals("buzz")) {
      continue orig;
    }
  }
  // other code comes here...
}

编辑: 好吧,看起来没有这样的等价物(嘿 - Jon Skeet 本人说没有,这就解决了;)). 因此,对于我来说(在其 Java 等效版本中),“解决方案”是:


for(String a : foo) {
  bool foundBuzz = false;
  for (String b : bar) {
    if (b.equals("buzz")) {
      foundBuzz = true;
      break;
    }
  }
  if (foundBuzz) {
    continue;
  }
  // other code comes here...
}

希望最后才会消失:https://github.com/dotnet/csharplang/issues/869 和 https://visualstudio.uservoice.com/forums/121579-visual-studio-ide/suggestions/6340889-allow-the-c-break-statement-to-terminate-sever(无法投票)。 - greenoldman
C# 应该有一天会推出 "continue {label}" 和 "break {label}" 功能 - 请参见 https://github.com/dotnet/csharplang/issues/869 并投票。 - Kind Contributor
6个回答

44

很抱歉,我不认为有相应的替代方法。您必须使用布尔值或者直接“跳转”到外部循环内部的结尾。这听起来比实际上还要麻烦,因为标签必须应用于语句,但我们不想在此处执行任何操作。然而,我认为这样做可以达到您的目的:

using System;

public class Test
{
    static void Main()
    {
        for (int i=0; i < 5; i++)
        {
            for (int j = 0; j < 5; j++)
            {
               Console.WriteLine("i={0} j={1}", i, j);
               if (j == i + 2)
               {
                   goto end_of_loop;   
               }
            }
            Console.WriteLine("After inner loop");
            end_of_loop: {}
        }
    }
}

然而,我强烈推荐您用另一种方式来表达它。我认为很少有情况下编码的可读性没有更好的提升方法。


17
C#дё­жњ‰gotoпјЊдЅ†жІЎжњ‰break/continue <label>有点令人惊讶。 - Rok Strniša
3
C#比Java更忠实于C语言的根源。它还具有结构体和指针! - Chris Rollins
等一下:@JonSkeet居然害怕这个?那我在这种情况下该怎么办? - tetri

11

另一种可能是使用内部循环创建一个函数:

void mainFunc(string[] foo, string[] bar)
{
  foreach (string a in foo)
    if (hasBuzz(bar))
      continue;
  // other code comes here...
}

bool hasBuzz(string[] bar)
{
  foreach (string b in bar)
    if (b.equals("buzz"))
      return true;
  return false;
}

我更喜欢这种方式,因为函数中的这种循环通常具有良好的语义(=> 良好的名称),因此可重用。 - Spoc

2
在VB.Net中,您只需要一个while循环和一个for循环,然后退出所需的作用域级别。
在C#中,也许是break;
这可能会打破内部循环并允许外部循环继续进行。

0

我认为你正在寻找简单的“continue”关键字... 然而,作为一个非Java程序员,我不太明白代码片段试图实现什么。

不过,考虑以下内容。

foreach(int i in new int[] {1,2,3,5,6,7})
{
    if(i % 2 == 0)
        continue;
    else
        Console.WriteLine(i.ToString());    
}

第4行的continue语句是指继续循环到下一个值。这里的输出将是1、3、5和7。
将“continue”替换为“break”,如下所示,
foreach(int i in new int[] {1,2,3,5,6,7})
{
    if(i % 2 == 0)
       break;
    else
        Console.WriteLine(i.ToString());    
}

将会输出1。Break指示循环终止,通常用于在满足条件时停止处理。

希望这能给你一些你想要的东西,但如果不是,请随时再问。


2
谢谢,但我知道“continue”和“break”的区别。;-) 问题是:我有两个嵌套的循环。如果内部循环中发生某个特定条件,我想要“continue”外部循环。 - Epaga
2
抱歉 - 我不是故意教你学习基础的知识 - 错误在于我没有充分阅读问题... - ZombieSheep

0
你可以这样做:
for(int i=0; i< foo.Length -1 ; i++) {
  for (int j=0; j< bar.Length -1; j++) {
    if (condition) {
      break;
    }
    if(j != bar.Length -1)
        continue;
    /*The rest of the code that will not run if the previous loop doesn't go all the way*/
  }
}

1
问题在于其余的代码在嵌套循环之后,而不是在其中。 - Epaga
糟糕,我刚刚注意到在我的第一个示例中,我对“//在这里编码”注释的行有误。抱歉。 - Epaga
你可以在跳出循环之前设置一个标志,然后在循环后检查该标志。如果你真的想让你的代码形式化“结构化”,你可以设置j = bar.Length而不是使用“break”。 - Joel Coehoorn
j = bar.Length会运行当前的循环直到结束,这不是预期的结果 ;) - Sergio

0

我是C#的新手,我知道这是一个老问题,但是我想出了以下解决方案:

用法:

const string topLoopLabel = "topLoop";

Loop.ForEach(fooList, (fooItem, index, next) => 
{
    // ...
    Loop.For(0, (i) => i < bar.Length, (i) => i++, (index, next) => 
    {
        // ...
        if (condition) 
        {
            next(topLoopLabel);  
        }
        // ...
    });
    // ...
}, topLoopLabel);

在引擎盖下:
static class Loop {

    public delegate void Continue(string? label = null);

    public delegate void IndexedIterationHandler(int index, Continue next);

    public delegate void ListIterationHandler<T>(T item, int index, Continue next);

    private static Continue next = (label) => {
        throw new CancelledIterationException { Label = label };
    };

    public static void For(int initialIndex, Func<int, bool> indexCondition, Func<int, int> iterator, IndexedIterationHandler iterationHandler, string? label = null)
    {
        for (int i = initialIndex; indexCondition(i);)
        {
           OnIteration(() => iterationHandler(i, next));
           i = iterator(i);
        }
    }

    public static void ForEach<T>(IList<T> list, ListIterationHandler<T> iterationHandler, string? label = null) 
    {
        for (int i = 0; i < list.Count; i++)
        {
            OnIteration(() => iterationHandler(list[i], i, next));
        }
    }

    /*
     * other loop types can be defined here
     */

    private static void OnIteration(Action loopBody)
    {
        try
        {
            loopBody();
        }
        catch (CancelledIterationException e)
        {
            if (!String.IsNullOrEmpty(e.Label) && !String.Equals(e.Label, e))
            {
                throw;
            }
         }
    }

    [Serializable()]
    class CancelledIterationException : Exception
    {
        public required string? Label { get; init; }
    }
}

优点:

  • 没有goto或多个返回语句
  • 没有临时变量
  • 不同的循环可以轻松组合
  • 易于理解
  • 不需要为每个循环添加标签

缺点:

  • 正如您在底层看到的,异常被用来修改程序流程,这是一种反模式
  • 如果在顶层循环中调用下一个函数,并且该字符串参数不等于顶层循环的标签,则异常将无法捕获。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接