使用“goto”在开关中?

发布于 2024-10-12 20:16:10 字数 112 浏览 9 评论 0原文

我看到了一个建议的编码标准,内容为除非在 switch 语句中失败,否则永远不要使用 goto

我不跟。这个“异常”情况到底是什么样子,才能证明 goto 是合理的?

I've seen a suggested coding standard that reads Never use goto unless in a switch statement fall-through.

I don't follow. What exactly would this 'exception' case look like, that justifies a goto?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

千鲤 2024-10-19 20:16:10

此构造在 C# 中是非法的:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
   case 1:
       Console.WriteLine("variable is >= 1");
}

在 C++ 中,如果 variable = 2,它将运行两行。这可能是故意的,但很容易忘记第一个 case 标签末尾的 break; 。因此,他们在 C# 中将其定为非法。要模仿跌倒行为,您必须明确使用 goto 来表达您的意图:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
       goto case 1;
   case 1:
       Console.WriteLine("variable is >= 1");
       break;
}

也就是说,有 一些情况,其中 goto 实际上是解决该问题的一个很好的解决方案。 永远不要用“永远不要使用某些东西”的规则来关闭你的大脑 。如果它 100% 无用,那么它从一开始就不会存在于语言中。不要使用goto指南;这不是法律。

This construct is illegal in C#:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
   case 1:
       Console.WriteLine("variable is >= 1");
}

In C++, it would run both lines if variable = 2. It may be intentional but it's too easy to forget break; at the end of the first case label. For this reason, they have made it illegal in C#. To mimic the fall through behavior, you will have to explicitly use goto to express your intention:

switch (variable) {
   case 2: 
       Console.WriteLine("variable is >= 2");
       goto case 1;
   case 1:
       Console.WriteLine("variable is >= 1");
       break;
}

That said, there are a few cases where goto is actually a good solution for the problem. Never shut down your brain with "never use something" rules. If it were 100% useless, it wouldn't have existed in the language in the first place. Don't use goto is a guideline; it's not a law.

任性一次 2024-10-19 20:16:10

C# 拒绝让 case 隐式失败(除非 case 中没有代码),就像 C++ 中一样:您需要包含 break。要明确失败(或跳转到任何其他情况),您可以使用goto case。由于没有其他方法可以实现这种行为,因此大多数(合理的)编码标准都允许这样做。

switch(variable)
{
case 1:
case 2:
    // do something for 1 and 2
    goto case 3;
case 3:
case 4:
    // do something for 1, 2, 3 and 4
    break;
}

一个现实的例子(根据要求):

switch(typeOfPathName)
{
case "relative":
    pathName = Path.Combine(currentPath, pathName);
    goto case "absolute";

case "expand":
    pathName = Environment.ExpandEnvironmentVariables(pathName);
    goto case "absolute";

case "absolute":
    using (var file = new FileStream(pathName))
    { ... }
    break;

case "registry":
    ...
    break;
}

C# refuses to let cases fall through implicitly (unless there is no code in the case) as in C++: you need to include break. To explicitly fall through (or to jump to any other case) you can use goto case. Since there is no other way to obtain this behaviour, most (sensible) coding standards will allow it.

switch(variable)
{
case 1:
case 2:
    // do something for 1 and 2
    goto case 3;
case 3:
case 4:
    // do something for 1, 2, 3 and 4
    break;
}

A realistic example (by request):

switch(typeOfPathName)
{
case "relative":
    pathName = Path.Combine(currentPath, pathName);
    goto case "absolute";

case "expand":
    pathName = Environment.ExpandEnvironmentVariables(pathName);
    goto case "absolute";

case "absolute":
    using (var file = new FileStream(pathName))
    { ... }
    break;

case "registry":
    ...
    break;
}
深白境迁sunset 2024-10-19 20:16:10
   public enum ExitAction {
        Cancel,
        LogAndExit,
        Exit
    }

ExitAction action = ExitAction.LogAndExit;
switch (action) {
    case ExitAction.Cancel:
        break;
    case ExitAction.LogAndExit:
        Log("Exiting");
        goto case ExitAction.Exit;
    case ExitAction.Exit:
        Quit();
        break;
}

比这更简洁(特别是如果您在 Quit() 中做了更多工作)

ExitAction action = ExitAction.LogAndExit;
switch (action) {
    case ExitAction.Cancel:
        break;
    case ExitAction.LogAndExit:
        Log("Exiting");
        Quit();
        break;
    case ExitAction.Exit:
        Quit();
        break;
}
   public enum ExitAction {
        Cancel,
        LogAndExit,
        Exit
    }

This is neater

ExitAction action = ExitAction.LogAndExit;
switch (action) {
    case ExitAction.Cancel:
        break;
    case ExitAction.LogAndExit:
        Log("Exiting");
        goto case ExitAction.Exit;
    case ExitAction.Exit:
        Quit();
        break;
}

Than this (especially if you do more work in Quit())

ExitAction action = ExitAction.LogAndExit;
switch (action) {
    case ExitAction.Cancel:
        break;
    case ExitAction.LogAndExit:
        Log("Exiting");
        Quit();
        break;
    case ExitAction.Exit:
        Quit();
        break;
}
森林迷了鹿 2024-10-19 20:16:10

除了使用 goto case 之外,您还可以 goto 另一个 case 子句中的标签:

    switch(i) {
    case "0":
        // do some stuff
        break;
    case "1":
        // other stuff, then "fall through" to next case clause
        goto Case2;
    case "2":
    Case2:
        break;
    }

这样,您就可以跳转到另一个 case 子句,而不必担心值或类型的表达式。

不过,某种可以替代 break 的显式“fallthrough”关键字会很好......

In addition to using goto case, you can goto a label that is in another case clause:

    switch(i) {
    case "0":
        // do some stuff
        break;
    case "1":
        // other stuff, then "fall through" to next case clause
        goto Case2;
    case "2":
    Case2:
        break;
    }

This way, you can jump to another case clause without worrying about the value or type of the expression.

Some sort of explicit "fallthrough" keyword that can be substituted for break would have been nice, though...

意中人 2024-10-19 20:16:10

这是 C# 允许 switch case “失败”的唯一方法。在 C# 中(与 C、C++ 或 Java 不同),switch 语句中的 case 块必须以 break 或其他显式跳转语句结束。

It's the only way that C# allows a switch case 'fallthrough'. In C# (unlike C, C++ , or Java), a case block in a switch statement must end with a break or some other explicit jump statement.

夜血缘 2024-10-19 20:16:10

通过对 Mehrdad Afshari 上述建议的扩展,我绝不会主张简单地将某个构造作为“糟糕的代码”或“糟糕的编码实践”而放逐。甚至“goto”语句在宏伟的计划中也占有一席之地。认为它们是邪恶的教条之所以成为现实,并不是因为结构中存在任何固有的缺陷——而是因为它们被严重(且糟糕地)过度使用。

无论如何,克尼根和里奇认为,让案件败诉才是正确的做法。坦率地说,我更倾向于相信他们的推理,而不是整个华盛顿雷德蒙德任何人的想法。或者任何基于雷德蒙德任何人的智慧的教条。

如果您听到“永远不要使用 xxx”,请在心里加上“无原因”。教条地抛弃任何东西都是荒谬的。设备的存在是因为有制造它们的理由。事后看来,它们通常被称为“坏”,不是因为设备本身有任何故障,而是因为不完全理解它们的人对它们的使用不当。因此,该设备几乎不会“坏”。几乎总是不好的就是用户的理解能力。即使对于原子裂变和聚变也是如此。

我见过一些极其怪异的代码结构,其唯一的功能就是避免使用“goto”语句。更糟糕的是什么呢? “goto [label]”,还是 30 行恶心的代码,其功能是避免键入“goto [label]”?

在教条之前寻求知识。行动前三思。这些都是有用的建议。

By way of an extension to Mehrdad Afshari's advice above, I would never advocate simply exiling a construct as 'bad code' or 'bad coding practice'. Even 'goto' statements have their place in the grand scheme of things. The dogma that they are evil did not come to pass because of any inherent flaw in the construct - it was because they were heavily (and poorly) over-used.

In any case, Kernighan and Ritchie felt that allowing a case to fall through was the proper way to go. Frankly, I'm more inclined to trust their reasoning than anything that could conceivably come out of any mind in the whole of Redmond, Washington. Or any dogma that is predicated on the wisdom of any mind in Redmond.

If you ever hear 'Never use xxx', mentally append that with 'without cause'. Just tossing out anything dogmatically is ridiculous. Devices exist because there was a reason to make them. They are, in hindsight, usually referred to as 'bad' not because of any fault in the device itself, but rather because they were employed poorly by people who did not fully understand them. Thus, the device is hardly ever 'bad'. What is almost always bad is user comprehension. This is true even of atomic fission and fusion.

I've seen horrendously grotesque code structures whose sole function was to avoid the use of a 'goto' statement. What is worse? "goto [label]", or 30 lines of disgusting code whose function is to avoid having to type "goto [label]"?

Seek knowledge before dogma. Think before you act. These are useful advices.

走野 2024-10-19 20:16:10

我知道这是老话题,但问题仍然是现实的。我们可以使用下一个代码而不是带有 goto 语句的丑陋版本吗?

var variable = 2;
switch (variable)
{
case 2:
Console.WriteLine("variable is >= 2");
goto case 1;
case 1:
Console.WriteLine("variable is >= 1");
break;


}

可能会被替换为下一个更简洁的代码:

if (variable >= 2)
{
Console.WriteLine("variable is >= 2");
}
if (variable >= 1)
{
Console.WriteLine("variable is >= 1");
}

I know that is old topic but question is still actual. Could we use the next code instead ugly version with goto statement ?

var variable = 2;
switch (variable)
{
case 2:
Console.WriteLine("variable is >= 2");
goto case 1;
case 1:
Console.WriteLine("variable is >= 1");
break;


}

might be substituted with the next neater code:

if (variable >= 2)
{
Console.WriteLine("variable is >= 2");
}
if (variable >= 1)
{
Console.WriteLine("variable is >= 1");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文