例外

概要

処理中に発生した異常を例外(Exception)という形で上流の処理に通知できます。
通知された側は例外に応じて適切なハンドリングを行うことで、プログラム実行中の異常をコントロールします。
ただし、例外は重たい処理なので、要否を適切に判断する必要があります。

例外の定義

すべての例外はExceptionクラスを継承して定義されます。

public class HogeException : Exception
{
}

発生した異常の種類に応じた例外クラスを定義します。

  • IOException
  • SqlException etc...

例外の通知

例外クラスのインスタンスをスローします。
メッセージなどを指定可能です。

throw new HogeException("Exception occurred");

例外のハンドリング

try/catchステートメントでハンドリングします。

try
{
    throw new HogeException();
}
catch
{
    Console.WriteLine("Exception occurred")
}

例外の種類を指定したり、フィルターすることができます。
複数の例外のハンドリング処理を記述することもできま す。

catch (HogeException e)
{
     // 例外がHogeExceptionの場合に処理する
     Console.WriteLine(e.Message);
}
catch (FugaException e) when (e.Message == "a")
{
     // 例外がFugaExceptionかつ、Messageの値が"a"の場合に処理する
}
catch (FugaException e) when (e.Message == "b")
{
    // 例外がFugaExceptionかつ、Messageの値が"b"の場合に処理する
}
catch (Exception e)
{
     // それ以外の場合に処理する
}

上流で確実に処理される場合を除き、漏れを防ぐためにException型のハンドリング処理を入れます。
例外がハンドリングされなかった場合、アプリケーションは強制終了されてしまいます。

例外の再スロー

例外をcatchし、ログ出力などの処理を行った後に再スローすることができます。
ただし、再スロー方法次第では、スタックトレースのオリジナルの例外発生箇所の情報が失われます。
以下の方法でそれを回避することができます。

  • 何も指定せずにスローする
catch (HogeException ex)
{
     throw;
}
catch (HogeException ex)
{
     throw new HogeException(ex);
}
  • ExceptionDispatchInfoを使用する
catch (HogeException ex)
{
     ExceptionDispatchInfo.Capture(ex).Throw();
}

catchした例外インスタンスを指定してスローした場合、スタックトレースが失われます。
再スローされた例外は再スロー箇所を例外発生箇所としてスタックトレースに記録します。

catch (HogeException ex)
{
     throw ex;
}