switch case default 不該只是 default

除非,在很少數的情況,設計上接受 default 有預設合法行為,不然 switch case default 都應該即時拋出例外。

switch case 是一個很方便的分支點判斷邏輯,雖然會造成分支點過多讓程式難以測試(可以用工廠方法搭配反射與多型處理掉);但在一些簡單的情境上,免不了還是會使用。然而在最近的 Code Review 中,發現一些 switch case 上使用的錯誤,有增加日後程式漏洞的風險;因此想用這篇文章記錄下來。

假設有以下程式碼:

public enum Employee
{
	Null,
	Engineer,
	Sales,
}

有了列舉,當然就要依照不同列舉新增對應的處理方式;於是很自然的加入了處理方法。

public void DealWithEmployee( Employee employee )
{
	switch (employee)
	{
		case Employee.Null:
			// Do someting..
			break;
		case Employee.Engineer:
			// Do someting..
			break;
		case Employee.Sales:
			// Do someting..
			break;
		default
			break;
	}
}

恩看起來不錯,但好像哪裡怪怪的;不過目前為止一切美好,就先這樣吧。然而新的列舉加進來了,這次要新增的是 ProductManager。

新的列舉變成這樣:

public enum Employee
{
	Null,
	Engineer,
	Sales,
	ProductManager
}

然後很開心的跑了程式,編譯沒錯、跑起來也沒有跳例外;但在某一次選到了 ProductMananger 情況下,程式出現了奇怪的行為(有可能 crash、也有可能跑出錯誤的結果)。於是開始底爸葛,底阿底的開始想各種奇妙的情況,繞一大圈最後才發現原來是方法沒實作,由於 default 值直接跳出迴圈;沒能早期拋出例外,到了程式執行下好幾步才被某個例外觸發。

解決方法很簡單,就是在 default 值拋出例外,早期發現早期治療:

這是一個誇張的例子,實務上會發生的機率並不高(除非加入 enum 和負責實作的人不同人且溝通不良);Resharper 套件也會提示要加入 default 值跳出例外。但寫程式的是人,難免會有想要偷懶的時候;這時就得靠自身觀念把關,除非,在很少數的情況,設計上接受 default 有預設合法行為,不然都應該即時拋出例外。