SwitchExpressionException の原因と直し方
switch式が全てのパターンを網羅していないとき、コンパイラは警告を出しますが止めません。網羅されていない値が実際に渡された瞬間に実行時エラーになります。
エラーメッセージの読み方
Unhandled exception. System.Runtime.CompilerServices.SwitchExpressionException: Non-exhaustive switch expression failed to match its input.
System.Runtime.CompilerServices- 名前空間 — System なら標準の基本例外です
SwitchExpressionException- 例外クラス — 何が起きたか。ここを検索するのが最短です
Non-exhaustive switch expression failed to match its input.- 詳細メッセージ — どの値が問題だったか
at Program.Describe(Int32 n) in Program.cs:line 3- 発生箇所 — スタックトレースの先頭行
このエラーが出る典型パターン
パターン1
1 class Program { 2 static string Describe(int n) { 3 return n switch { 4 1 => "one", 5 2 => "two", 6 }; 7 } 8 static void Main(string[] args) { 9 System.Console.WriteLine(Describe(3)); ^ 10 } 11 }
switch式は網羅していないパターンがあると、そこに来たときだけ実行時に失敗します。コンパイラは警告は出しますが止めてはくれません。
直し方: 3 を 1 にします。
パターン2
1 class Program { 2 static string Grade(int score) { 3 return score switch { 4 90 => "A", 5 80 => "B", 6 70 => "C", 7 }; 8 } 9 static void Main(string[] args) { 10 System.Console.WriteLine(Grade(60)); ^ 11 } 12 }
点数を細かく分岐させるほど、想定外の値を見落としやすくなります。_ => "..."のような既定パターンを最後に置くと防げます。
直し方: 60 を 80 にします。
パターン3
1 class Program { 2 static string Label(int code) { 3 return code switch { 4 200 => "OK", 5 404 => "Not Found", 6 }; 7 } 8 static void Main(string[] args) { 9 System.Console.WriteLine(Label(500)); ^ 10 } 11 }
HTTPステータスコードのように種類が多い値をswitch式で扱うときほど、既定パターンの用意が重要になります。
直し方: 500 を 200 にします。
パターン4
1 class Program { 2 static string Weekday(int n) { 3 return n switch { 4 1 => "Mon", 5 2 => "Tue", 6 3 => "Wed", 7 }; 8 } 9 static void Main(string[] args) { 10 System.Console.WriteLine(Weekday(4)); ^ 11 } 12 }
3つのパターンしか用意していないため、それ以外の値が来るとSwitchExpressionExceptionになります。
直し方: 4 を 2 にします。
パターン5
1 class Program { 2 static string Size(int n) { 3 return n switch { 4 1 => "S", 5 2 => "M", 6 3 => "L", 7 }; 8 } 9 static void Main(string[] args) { 10 System.Console.WriteLine(Size(0 )); ^ 11 } 12 }
サイズ表現も同様です。想定していない値をコンパイラは検出できません。
直し方: 0 を 3 にします。
よくある誤解
警告(CS8509)が出ていても、ビルドは成功してしまいます。見た目上は正常に動くコードに見えるため、想定外の入力が来るまで気づきにくいバグです。
実務での勘所
switch式の網羅性チェックが警告どまりなのは、パターンの対象が必ずしも「有限個の値をコンパイラが数え上げられる」ものとは限らないためです。enum型のような値の種類が確定している対象なら網羅性を完全に検証できますが、int型や、後から新しい実装クラスが追加されうるインターフェース型を対象にしたパターンマッチでは、理論上すべてのケースを列挙しきれません。コンパイラが確実に判定できる範囲では警告してくれますが、それを鵜呑みにせず、default分岐や例外送出を明示的に用意しておくのが安全です。