C# 的 switch 看似簡單,實則暗藏嚴格規則與強大模式匹配能力。本文揭示四大「你可能不知道」的特性,助你寫出更安全、更優雅的分支代碼。
break 或 gotoint i = 0;
switch (i) {
case 0:
Console.WriteLine("0");
// 編譯錯誤 CS0163: Control cannot fall through from one case label to another
case 1:
Console.WriteLine("1");
break;
}
規則:C# 要求每個 case 塊必須以 break、return、throw 或 goto 結束,**禁止隱式貫穿**。這消除了 C/C++ 中漏寫 break 導致的經典 Bug。
goto caseswitch (i) {
case 0:
Console.WriteLine("0");
goto case 1; // 顯式跳轉,合法
case 1:
Console.WriteLine("1");
break;
}
case 標簽在 C# 中本質是標號,goto case 常量 / goto default 提供了受控的貫穿能力。
default 也不例外:不可隱式貫穿switch (i) {
case 0: DoSomething(); break;
default:
// 若此處無 break/return/goto,且非最後一個 case,仍報錯
LogDefault();
// 錯誤:Control cannot fall through...
}
即使 default 邏輯為空,也需顯式 break 或置於最後。
switch (i) {
case 0:
int y = 10; // 錯誤 CS0028: A local variable named 'y' cannot be declared in this scope
break;
case 1:
int y = 20; // 與 case 0 同層作用域,衝突!
break;
}
原因:switch 整體僅形成**單一聲明空間**,case 不創建新作用域。
case 0: {
int y = 10; // OK
break;
}
case 1: {
int y = 20; // OK
break;
}
int y;
switch (i) {
case 0: y = 10; break;
case 1: y = 20; break;
}
bool 也不夠聰明int M(bool b) {
switch (b) {
case true: return 1;
case false: return 0;
// 編譯錯誤 CS0161: 'M': not all code paths return a value
}
}
原理:編譯器不分析 bool 只有兩值的語義,僅按控制流圖判斷:switch 可能不進入任何 case (如未來擴展類型)、或 case 體內不返回。因此要求**所有路徑**顯式返回。
// 方案 1:default 兜底 (語義等價)
int M(bool b) {
switch (b) {
case true: return 1;
default: return 0; // 編譯器認可所有路徑覆蓋
}
}
// 方案 2:三元運算符 (更簡潔)
int M(bool b) => b ? 1 : 0;
// 屬性模式 + Switch 表達式 (C# 8)
string Describe(object o) => o switch {
int i when i > 0 => "正整數",
int i => "非正整數",
string s when s.Length > 10 => "長字符串",
null => "空引用",
_ => "其他類型"
};
表達式體自動保證窮盡性,無需 break,代碼更函數式、更安全。
| 特性 | C/C++ | C# (傳統) | C# 8+ 表達式 |
|---|---|---|---|
| 隱式 Fallthrough | 允許 (危險) | 禁止 (編譯錯誤) | 不存在 |
| 顯式 Fallthrough | 無需關鍵字 | goto case | 多模式逗號分隔 |
| Case 作用域 | 同 Switch | 同 Switch (需 { } 隔離) | 獨立 |
| 窮盡性檢查 | 無 | 控制流分析 | 模式匹配強制 |