编译错误 · 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# 把它定为编译错误;空标签叠加仍合法,用于共享分支体。
排查清单
- 每个有代码的 case 以
break;、return …;或throw …;结尾。 - 多个值一段逻辑 → 叠标签,中间零语句。
- 别忘了
default:——它也要自己的break;。 - 从 C/C++/Java 过来的:没错,C# 就是更严——故意的。