編譯錯誤 · 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# 把它定為編譯錯誤;空標籤疊加仍合法,用於共享分支體。

排查清單