編譯錯誤 · 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# 就是更嚴——故意的。