我该如何摆脱这个goto?

How do I get rid of this goto?

我刚刚开始一个职位,在工作日结束时,我通过慢慢阅读我们的代码库来等待流量。我遇到了这一点,即使在白板上花了相当长的时间后,我仍然想不出提取 goto 的方法。有没有办法消除这种跳跃?

public void MyUpdate(MyType foo)
{
    /*Prep code for the loops*/        
    foreach (Thing bar in something)
    {
        foreach (Collection item in bar.Stuff)
        {
            Data dataRX = item.First;
            if (dataRX != null && dataRX.ID.Equals(globalNonsense.ID))
            {
                // Update Data with the latest changes
                dataRX.fooBuddy = foo;
                goto exitLoops;
            }
        }
    }

    exitLoops: ;
}

将内部循环移动到一个方法,并根据其 return 值有条件地中断。

这不是很好,但如果不实施全新的算法,这似乎是最简单的方法:

foreach (Thing bar in something)
{
    bool exitLoop = false;
    foreach (Collection item in bar.Stuff)
    {
        Data dataRX = item.First;
        if (dataRX != null && dataRX.ID.Equals(globalNonsense.ID))
        {
            // Update Data with the latest changes
            dataRX.fooBuddy = foo;
            exitLoop = true;
            break;
        }
    }

    if (exitLoop) break;
}

既然标签exitLoops在方法的最后,那么你可以简单地使用return退出方法,像这样:

if (dataRX != null && dataRX.ID.Equals(globalNonsense.ID))
{
    // Update Data with the latest changes
    dataRX.fooBuddy = foo;
    return;
}

另一种方法是使用这样的标志:

bool done = false;

foreach (Thing bar in something)
{
    foreach (Collection item in bar.Stuff)
    {
        Data dataRX = item.First;
        if (dataRX != null && dataRX.ID.Equals(globalNonsense.ID))
        {
            // Update Data with the latest changes
            dataRX.fooBuddy = foo;
            done = true;
            break;
        }
    }

    if(done)
        break;
}

即使标签后面有一些代码,您也可以使用第二种方法。

或者,您可以使用 LINQ 执行此操作:

public void MyUpdate(MyType foo)
{
    Thing dummy = something.FirstOrDefault(bar => bar.Stuff.SkipWhile((item) => 
    {
        Data dataRx = item.First;
        if (dataRx != null && dataRx.ID.Equals(globalNonsense.ID))
        {
            dataRx.fooBuddy = foo;
            return false;
        }
        else
        {
            return true;
        }
    }).Count() != 0);
}

如果您使用 foreach,则需要 breakreturn。但如果没有 breakreturngoto,则有此选项:

public void MyUpdate(MyType foo)
{
    bool stop = false;

    /*Prep code for the loops*/        
    for (var i = 0; !stop && (i < something.Count); i++)
    {
        for (var j = 0; !stop && (j < something[i].Stuff.Count); j++)
        {
            Data dataRX = something[i].Stuff[j].First;
            if (dataRX != null && dataRX.ID.Equals(globalNonsense.ID))
            {
                // Update Data with the latest changes
                dataRX.fooBuddy = foo;
                stop = true;
            }
        }
    }
}