编译错误 · error CS0163

控制不能从一个 case 标签贯穿到另一个

一个 case 干完了活,然后……继续流进了下一个 case。在 C 和 C++ 里这是合法的,并制造了几十年的 bug;在 C# 里编译器直接拒绝。每个非空的 case 必须以 break;、return; 或 throw; 结尾。

亲眼看它发生

int d = 1;
switch (d)
{
    case 1:
        Console.WriteLine("one");
        // 没有 break——控制会"贯穿"进 case 2
    case 2:
        Console.WriteLine("two");
        break;
}
int d = 1;
switch (d)
{
    case 1:
        Console.WriteLine("one");
        break;               // 把控制交回去——完事
    case 2:
        Console.WriteLine("two");
        break;
}

但你想要的多半是栈式标签

大家说"贯穿"时,真正想要的通常是多个值共享一段逻辑。这是合法的——把标签叠起来,中间不放东西:

void Classify(int day)
{
    switch (day)
    {
        case 6:
        case 7:                      // 6 和 7 共用这个分支——标签之间没有代码
            Console.WriteLine("weekend");
            break;
        default:
            Console.WriteLine("weekday");
            break;
    }
}

Classify(7);
Classify(3);

规则很精确:空的标签可以叠(什么都没贯穿);带代码的标签必须自己收尾。

为什么 C# 比 C++ 严——为什么这是好事

在 C++ 里忘写 break 会静默执行下一个 case 的代码。Apple 著名的 goto fail 漏洞正是这个形状。C# 的设计者把漏写 break 定为编译错误,用一点点便利换掉了一整类 bug。踩到 CS0163 时,编译器不是在唠叨——是语言在替你关上一扇 50 年的老陷阱。

编译器认可的收尾方式

int Apply(char op, int a, int b)
{
    switch (op)
    {
        case '+':
            return a + b;              // return 结束 case——不需要 break
        case '*':
            return a * b;
        default:
            throw new Exception("unknown operator");   // throw 也能收尾
    }
}

Console.WriteLine("result: " + Apply('*', 2, 4));

break 退出 switch;return 退出整个方法;throw 轰然退场。三者任选其一都满足规则——但"顺着跑到 case 末尾"永远不行。

常见问答

怎么修 C# 里的 CS0163?

有代码的 case 必须以 break、return 或 throw 结尾。多个值共用一段逻辑时,把标签叠起来、中间不放语句。

为什么 C# 禁止 switch 贯穿?

C/C++ 里漏 break 会静默执行下一个 case——Apple 的 goto fail 漏洞就是这种形状。C# 把它定为编译错误;空标签叠加仍合法,用于共享分支体。

排查清单