例外(exception)とは
例外(exception)とは、 本来ならばプログラム中で起こってはいけないことが起こってしまうことです。
堅牢なプログラムを作成するためには、 例外が起こったときでも、しっかりと例外処理を行う必要があります。
上述したように、例外処理専用の構文を用いなくても例外処理を行えます。
しかし、上述したような方法にはいくつか欠点があります。
欠点を以下に挙げます。
- 例外の検出処理を書かなければいけない
- 正常動作部と例外処理部のコードが分かりにくくなる。
- 関数を使用する人に例外処理(異常が対する処理)を行うことを強制出来ない。
- 関数を呼び出すたびに例外処理用のコードを書く必要がある。
throw
例外が発生する可能性のある側では、 throw 文を使って例外が起こったことを利用側に知らせます。
throw <例外クラスのインスタンス>
想定外のことが起こった場所にこのthrow 文を挿入します。 このような処理を「例外を投げる」といいます。 例外が投げられると、正常動作部の処理は中断され、例外処理部が呼び出されます。
throw 文によって投げられる例外は、 System.Exception クラスの派生クラスのインスタンスです。 それ以外のクラスのインスタンスを throw することは出来ません。
例えば、throw new Exception(); というようにします。
try { // 処理 throw <例外クラスのインスタンス> } catch(Exception ex) { // 例外が発生した時の処理 }
次に、関数利用側、すなわち、例外を処理する側では、 try-catch-finally 文を使って例外を処理します。 try-catch-finally 文は以下のようにして使用します。
try { // 処理 throw <例外クラスのインスタンス> } catch(Exception ex) { // 例外が発生した時の処理 } finally { // 正常でも例外が発生した場合でも実行する処理 }
例外処理の指針
一般に、tyr-catch を用いた例外処理は、 if 文などを使った値のチェックに比べて、 実行速度が遅いといわれています。
try ブロックで囲んだだけでは(例外が発生しなければ)ほとんどオーバーヘッドはないのですが、 例外発生時には少し大き目のコストが発生します。
例外フィルター
C# Ver.6で、例外のcatch句に続けてwhenと書くことで、catchしたい例外の条件を書けるようになりました。 この機能を例外フィルター(exception filter)といいます。
用途としては、例えば、以下のように、複数の種類の例外に対して、同じ例外処理を掛けたい場合があります。
try { // 処理 } catch (DirectoryNotFoundException e) { // 例外が発生した場合の処理 Console.WriteLine(e); } catch (FileNotFoundException e) { // 例外が発生した場合の処理 Console.WriteLine(e); }
こういったときに同一の例外処理を行うためにフィルターをかけたコードとすることが可能になりました。
try { throw new FileNotFoundException("Test throw!!"); } catch (Exception ex) when (ex is FileNotFoundException || ex is DirectoryNotFoundException) { // 1. 指定した例外が発生した場合の処理 Console.WriteLine(ex.Message); } catch { // 2. そのほかの例外が発生した場合の処理 }
ただ、下記のように「Exceptionクラスそのものの例外オブジェクト」の場合は「2. そのほかの例外が発生した場合の処理」で処理されるので注意してください。
try { throw new Exception("Test throw!!"); } catch (Exception ex) when (ex is FileNotFoundException || ex is DirectoryNotFoundException) { // 1. 指定した例外が発生した場合の処理 Console.WriteLine(ex.Message); } catch { // 2. そのほかの例外が発生した場合の処理 }