在C#中正确使用GOTO吗

时间:2012-11-29 20:16:19

标签: c# goto

我正在跟踪一些代码,并向下面发送一个列表,以从列表中删除某些项目。

这是使用goto的正确方法吗?它甚至是必要的吗?你是不是只编辑了第二个if if else,并继续处理列表而不需要goto? (这是我第一次见到BASIC之外的goto。)

public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
    {
        if (src == null)
            return null;
    checkAB01:
        for (int i = 0; i < src.Count; i++)
        {
            ClientEntity info = src[i];
            if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
                    &&
                    info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
                )
            {
                src.Remove(info);
                goto checkAB01;
            }

            if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
                &&
                (info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
            {
                src.Remove(info);
                goto checkAB01;
            }
        }
        return src;
    }

5 个答案:

答案 0 :(得分:4)

LINQ怎么样?

public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
    if (src == null)
        return null;

    return (from info in src.AsEnumerable<ClientEntity>()
            where !(!String.IsNullOrWhiteSpace(info.ProductNumber) &&
                    info.CancelledByReliantSyncAB01 == (bool?)true)
            where !(String.IsNullOrWhitespace(info.PartnerContract) &&
                    String.IsNullOrWhiteSpace(info.ProductNumber))
            select info).ToList();
}

答案 1 :(得分:2)

不,这不是使用goto的正确方法,它只是一个不知道如何从列表中正确删除项目的人的替代品。 (向后迭代以防止跳过元素)

public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
    if (src == null)
        return null;

    for (int i = src.Count - 1; i >= 0; i--)
    {
        ClientEntity info = src[i];
        if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
                &&
                info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
            )
        {
            src.RemoveAt(i);
        }

        if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
            &&
            (info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
        {
            src.RemoveAt(i);
        }
    }
    return src;
}

答案 2 :(得分:2)

我认为编写此代码的人不知道如何从迭代集合中删除项目。这些产品的原因是,一旦项目被删除,集合就会变小,这可能会导致迭代错误。

更好的一天是做一个反向循环。这样,您不必在删除后重复整个列表。下面的代码可以正常工作。

for (int i = src.Count - 1; i >= 0; i--) {
    src.Remove(src[i]);
}

答案 3 :(得分:2)

正如其他人所说,这是goto的使用率很低(应该很少,如果有的话),

总的来说,实施效率非常低。看起来它从0..N循环直到它移除了某些东西,然后从0..N(现在少了1)再次开始直到它移除了某些东西,依此类推。更糟糕的是,Remove再次呼叫 从0..N开始寻找要删除的项目。

如果找不到任何要删除的内容,则返回。最好只做一个反向循环删除条目RemoveAt然后返回。

public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
    if (src == null)
        return null;

    for (int i = src.Count - 1; i >= 0; i--)
    {
        ClientEntity info = src[i];
        if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
            &&
            info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true)
        {
            src.RemoveAt(i);
        }
        else if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
            &&
            (info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
        {
            src.RemoveAt(i);
        }
    }

    return src;
}

另外,我在那里添加了elseif:执行另一个 if检查似乎很危险,这可能是真的,并尝试重新删除相同的项目(特别是在改变指数)。

编辑:如果我们谈论可读的可用代码,我会将检查移到单独的方法中:

public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
    if (src == null)
        return null;

    for (int i = src.Count - 1; i >= 0; i--)
    {
        if (ShouldClientNotSendBack(src[i]))
            src.RemoveAt(i);
    }

    return src;
}

private static bool ShouldClientNotSendBack(ClientEntity info)
{
    if (!String.IsNullOrWhiteSpace(info.ProductNumber) && info.CancelledByReliantSyncAB01 == true)
    {
        return true;
    }

    if (!String.IsNullOrWhiteSpace(info.PartnerContract))
    {
        return true;
    }

    return false;
}

甚至可以考虑调整ShouldClientNotSendBack方法和/或名称(甚至可能将两组if检查移动到具有明确名称的单个方法),但我认为这是一个重大改进。

EDITx2:事实上,我会强烈考虑使用该方法。该方法在接收输入集合时显然返回IList<ClientEntity>,这通常会向开发人员传达创建新列表,而实际上它实际上是变异现有列表并返回相同的列表实例。要么让它返回一个新列表(因此你应该更改循环代码以添加到新列表而不是从现有列表中删除)或删除返回类型,这样就更明显它正在改变传递的列表参数。

答案 4 :(得分:2)

正如我在评论中所述,在C#中使用goto没有“正确”的方法。根据其定义,关键字是一个kludge;如果开发人员希望逐行翻译ASM或BASIC或其他语言的程序而没有定义的代码块,它隐藏了“跳跃”,那么它就是C / C ++的回归,其中包括它“以防万一”。过去常常进入他们之间。任何使用它的算法都可以重构而不必这样做,并且生成的算法将更具可读性。

在这种情况下:

public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
    if (src == null)
        return null;

    for (int i = src.Count-1; i>=0; i--)
    {
        ClientEntity info = src[i];
        if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
                &&
                info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
            )
        {
            src.Remove(info);
            continue;
        }

        if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
            &&
            (info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
        {
            src.Remove(info);
            continue;
        }
    }
    return src;
}

正如Chris Sinclair的回答所示,由于循环中条件的“或者/或”隐式结构,continue语句不是必需的,但是我喜欢它们,因为它们显示编码器没有任何来自将指向循环结束的那一点,而不必阅读其余部分来确定。

如果您愿意,可以从前到后遍历列表,如果删除了某个项目,则在继续之前递减i,以便循环将保持其在列表中的当前位置。有些人可能会说不这样做,因为对计数器的操作使得理解算法变得更加困难(并且因为在每次迭代时确定列表的计数稍微慢一些),但它在性能和可读性方面仍然要好得多。 goto