C# 中如何在没有标志变量的情况下跳出 2 个循环?

问题描述 投票:0回答:18

作为一个简单的例子,假设我有以下网格,并且我正在寻找特定的单元格值。 找到后我不再需要处理循环。

foreach(DataGridViewRow row in grid.Rows)
{
    foreach(DataGridViewCell cell in row.Cells)
    {
        if(cell.Value == myValue)
        {
            //Do Something useful
            //break out of both foreach loops.
        }
    }
}

这是如何在 C# 中完成的。 在 Java 中,我可以使用标签来命名最外层循环,然后打破该循环,但我似乎无法在 C# 中找到等效项。

在 C# 中实现此目的最简洁的方法是什么? 我知道我可以设置一个布尔标志,并在外循环中检查它以摆脱该标志,但它看起来太冗长了。

谢谢,

c# syntax
18个回答
92
投票

1

foreach(DataGridViewRow row in grid.Rows)
   foreach(DataGridView cell in row.Cells)
      if (cell.Value == somevalue) {
         // do stuff
         goto End;
      }
End:
   // more stuff

2

void Loop(grid) {
    foreach(row in grid.Rows)
       foreach(cell in row.Cells)
           if (something) {
               // do stuff   
               return;
           }
}

3

var cell = (from row in grid.Rows.OfType<DataGridViewRow>()
            from cell in row.Cells.OfType<DataGridViewCell>()
            where cell.Value == somevalue
            select cell
   ).FirstOrDefault();

if (cell != null) {
   // do stuff
}

61
投票

虽然上面的许多解决方案都是正确的并回答了你的问题,但我会退后一步问自己“是否有另一种方法可以更清楚地表示程序的语义?”

我倾向于这样编写代码:

var query = from row in grid.Rows
            from cell in row.Cells
            where cell.Value == myValue
            select cell;
if (query.Any())
{
  // do something useful;
}

为什么要编写循环? 您想知道特定集合是否具有特定成员,因此请编写一个询问该问题的查询,然后检查答案。


39
投票

最令人愉快的方法是将第二个循环分解为一个函数,如下所示:

public void DoubleLoop()
{
    for(int i = 0; i < width; i++)
    {
        for(int j = 0; j < height; j++)
        {
            if(whatever[i][j]) break; // let's make this a "double" break
        }
    }
}

前往

public bool CheckWhatever(int whateverIndex)
{
    for(int j = 0; j < height; j++)
    {
        if(whatever[whateverIndex][j]) return false;
    }

    return true;
}

public void DoubleLoop()
{
    for(int i = 0; i < width; i++)
    {
        if(!CheckWhatever(i)) break;
    }
}

当然,您可以随意使用 LINQ 或其他方式来简化它(您也可以将

CheckWhatever
放入循环条件中。)这只是原理的详细演示。


23
投票

我只是将循环包装到一个函数中,并让函数返回作为退出解决方案循环的一种方式。


21
投票
        foreach (DataGridViewRow row in grid.Rows)
        {
            foreach (DataGridViewCell cell in row.Cells)
            {
                if (cell.Value == myValue)
                {
                    goto EndOfLoop;
                    //Do Something useful
                    //break out of both foreach loops.
                }
            }

        }
        EndOfLoop: ;

这会起作用,但我建议使用布尔标志。

编辑: 只是在这里添加一点警告;使用 goto 通常被认为是不好的做法,因为它们很快会导致意大利面条式代码(几乎)无法维护。话虽如此,它已包含在 C# 语言中,并且可供使用,因此显然有人相信它具有有效的用法。了解该功能的存在并谨慎使用。


15
投票

为了完整起见,还有错误的做法:

try
{
    foreach(DataGridViewRow row in grid.Rows)
        foreach(DataGridViewCell cell in row.Cells)
            if(cell.Value == myValue)
               throw new FoundItemException(cell);
}
catch (FoundItemException ex)
{
    //Do Something useful with ex.item
}

13
投票

C# 有 goto 语句。事实上,MSDN 上的示例使用它来打破双重嵌套循环。


8
投票

最好的方法是不要这样做。 严重地;如果您想在嵌套循环中找到某些内容的第一次出现,然后完成查找,那么您要做的不是检查每个元素,这正是 foreach 构造的明确作用。 我建议在循环不变式中使用带有终止标志的常规 for 循环。


6
投票

这是 for 循环的附加解决方案:

bool nextStep = true;
for (int x = 0; x < width && nextStep; x++) {
    for (int y = 0; y < height && nextStep; y++) {
        nextStep = IsBreakConditionFalse(x, y);
    }
}

5
投票

您可以编写一个在一般情况下实现 IEnumerator 的类,然后您的枚举代码如下所示:

foreach (Foo foo in someClass.Items) {
    foreach (Bar bar in foo.Items) {
        foreach (Baz baz in bar.Items) {
            yield return baz;
        }
    }
}

// and later in client code

MyEnumerator e = new MyEnumerator(someClass);
foreach (Baz baz in e) {
    if (baz == myValue) {
        // do something useful
        break;
    }
 }

2
投票
  1. 按照建议使用 go to as PeterAllenWebb。
  2. 将两个 for 每个循环包装成一个函数,当你想中断时返回。

做了一些谷歌搜索,这里是 MSDN 论坛上的类似的问题


2
投票
  //describe how to find interesting cells
var query = from row in grid.Rows.OfType<DataGridViewRow>()
            from cell in row.Cells.OfType<DataGridViewCell>()
            where cell.Value == myValue
            select cell;
  //nab the first cell that matches, if any
DataGridViewCell theCell = query.FirstOrDefault();

  //see if we got one
if (theCell != null)
{
  //Do something with theCell
}

1
投票

将其放入函数中并在找到东西时使用

return
语句。
最后返回一个空值 - 表示未找到搜索的项目。


0
投票

您可以修改循环变量:

for (int i = 0; i < width; i++)
{
    for (int j = 0; j < height; j++)
    {
        if (NeedToBreak())
        {
            i = width;
            j = height; 
        }
    }

}

0
投票

还没有测试过...但是这样的东西可能会起作用

            Action dostuff =  () =>
            {

            }
        foreach (DataGridViewRow row in grid.Rows)
            foreach (DataGridViewCell cell in row.Cells)
                if (cell.Value == myValue)
                    goto A:

        A: dostuff();

0
投票

我认为你可以使用自定义异常,例如:

private class CustomException : ScriptException
{
  public CustomException()
  {
  }
}

try
{
    foreach(DataGridViewRow row in grid.Rows)
    {
        foreach(DataGridViewCell cell in row.Cells)
        {
            if(cell.Value == myValue)
                throw new CustomException();
        }
    }
}
catch(CustomException)
{ }

0
投票
int i;
int j;
int flag = 0; // Flag used to break out of the nested loop.
char ballonColor;

if (b == NULL || b->board == NULL) { // Checks for a null board.
    flag = 0;
}
else {
    for (i = 0; i < b->rows && !flag; i++) { // Checks if the board is filled with air (no balloons).
        for (j = 0; j <= b->cols && !flag; j++) {
            if (b->board[i][j] != None) {
                flag = 1;
            }
        }
    }
}

if (flag == 0) {
    return 0;
}
else {
    for (i = 0; i < b->rows && !flag; i++) { //
        for (j = 0; j <= b->cols && !flag; j++) {
            if (b->board[i][j] != None) {
                ballonColor = b->board[i][j];
                if (i == 0) { // Top Row
                    if (j == 0) {
                        if (b->board[i + 1][j] == ballonColor || b->board[i][j + 1] == ballonColor) {
                            return 1;
                        }
                    }
                    else if (j == b->cols) {
                        if (b->board[i + 1][j] == ballonColor || b->board[i][j - 1] == ballonColor) {
                            return 1;
                        }
                    }
                    else {
                        if (b->board[i + 1][j] == ballonColor || b->board[i][j + 1] == ballonColor || b->board[i][j - 1] == ballonColor) {
                            return 1;
                        }
                    }
                }
                else if (i == (b->rows - 1)) { // Bottom Row
                    if (j == 0) {
                        if (b->board[i - 1][j] == ballonColor || b->board[i][j + 1] == ballonColor) {
                            return 1;
                        }
                    }
                    else if (j == b->cols) {
                        if (b->board[i - 1][j] == ballonColor || b->board[i][j - 1] == ballonColor) {
                            return 1;
                        }
                    }
                    else {
                        if (b->board[i - 1][j] == ballonColor || b->board[i][j + 1] == ballonColor || b->board[i][j - 1] == ballonColor) {
                            return 1;
                        }
                    }
                }
                else { // 
                    if (j == 0) {
                        if (b->board[i + 1][j] == ballonColor || b->board[i - 1][j] == ballonColor || b->board[i][j + 1] == ballonColor) {
                            return 1;
                        }
                    }
                    else if (j == b->cols) {
                        if (b->board[i + 1][j] == ballonColor || b->board[i - 1][j] == ballonColor || b->board[i][j - 1] == ballonColor) {
                            return 1;
                        }
                    }
                    else {
                        if (b->board[i + 1][j] == ballonColor || b->board[i - 1][j] == ballonColor || b->board[i][j + 1] == ballonColor || b->board[i][j - 1] == ballonColor) {
                            return 1;
                        }
                    }
                }
            }
        }
    }
}

return 0;

0
投票

@d3rbastl3r 解决方案的另一个变体:

var isFound = false;
foreach(var x in XX)
{
    foreach(var y in YY)
    {
        if(condition)
        {
            isFound = true;
            break;
        }
    }
    if(isFound)
        break;
}
© www.soinside.com 2019 - 2024. All rights reserved.