例外処理

プログラミングC# 第6版 6.3.1


C#における例外処理のお話。C++にもありましたね。

まずは基本の実装例です。

using System;

class Program {
    static void Main() {
        try {
            Foo();
        }
        catch(Exception e) {
            Console.WriteLine("catch実行:"+e);
        }
        finally {
            Console.WriteLine("finally実行");
        }
    }
    
    static void Foo () {
        throw new Exception("error in Foo");
    }
}
$ main
catch実行:System.Exception: error in Foo
   場所 Program.Main()
finally実行

try内でスロー(発生)した例外をcatchでキャッチします。finallyは例外が発生したかしないかに限らずに常に呼ばれます。

キャッチした例外を再スローすることもできます。

using System;

class Program {
    static void Main() {
        try {
            Foo();
        }
        catch(Exception e) {
            Console.WriteLine("catch2実行:"+e);
        }
        finally {
            Console.WriteLine("finally2実行");
        }
    }
    
    static void Foo () {
        try {
            throw new Exception("error in Foo");
        }
        catch(Exception e) {
            Console.WriteLine("catch1実行:"+e);
            // 再スローする
            throw;
        }
        finally {
            Console.WriteLine("finally1実行");
        }
    }
}
$ main
catch1実行:System.Exception: error in Foo
   場所 Program.Foo()
finally1実行
catch2実行:System.Exception: error in Foo
   場所 Program.Foo()
   場所 Program.Main()
finally2実行

引数なしのthrow呼び出しで再スローとなります。

また新しい例外をスローする際に、既存の例外を引数に渡すことでInnerExceptionとして登録することができます。

そしてcatch先で登録されているInnerExceptionを取り出すことができます。

using System;

class Program {
    static void Main() {
        try {
            Foo();
        }
        catch(Exception e) {
            Console.WriteLine("catch2実行:"+e);
            
            // InnerExceptionとして登録されている例外を全て表示する
            Exception current = e;
            while( current != null ) {
                
                Console.WriteLine("InnerException:"+current);
                current = current.InnerException;
            }
        }
        finally {
            Console.WriteLine("finally2実行");
        }
    }
    
    static void Foo () {
        try {
            throw new Exception("error in Foo");
        }
        catch(Exception e) {
            Console.WriteLine("catch1実行:"+e);
            
            // eをInnerExceptionとして登録して再スローする
            throw new Exception("再スロー",e);
        }
        finally {
            Console.WriteLine("finally1実行");
        }
    }
}
$ main
catch1実行:System.Exception: error in Foo
   場所 Program.Foo()
finally1実行
catch2実行:System.Exception: 再スロー ---> System.Exception: error in Foo
   場所 Program.Foo()
   --- 内部例外スタック トレースの終わり ---
   場所 Program.Foo()
   場所 Program.Main()
InnerException:System.Exception: 再スロー ---> System.Exception: error in Foo
   場所 Program.Foo()
   --- 内部例外スタック トレースの終わり ---
   場所 Program.Foo()
   場所 Program.Main()
InnerException:System.Exception: error in Foo
   場所 Program.Foo()
finally2実行