現在ログインしていません。
新規アカウント作成
ログイン

未処理の例外をキャッチする

例外をキャッチして何かの処理を行いたい場合VBならば、TryCatchを、C#ならばtrycatchを使用します。

例外のキャッチは例外が発生する可能性を事前に予測しており、その例外が発生したときに明確にやるべきことがある場合のみ記述します。その理由は、想定外の例外が発生した場合アプリケーションの状態は文字通り想定外であり、扱っているデータが正しいことが保証できず、またロジックが想定どおり動作することも保証できないからです。ですから、Try~Catchはプログラムの中で頻繁に登場するのではなく、要所要所でのみ登場することになります。

それでは、Try~Catchで補足しない未処理の例外が発生した場合に何かロジックを実行するにはどうしたらよいでしょうか?多くの場合、例外情報をログに出力したり、ユーザー向けに何かメッセージを表示する、特定の終了コードを返すなどが実行したいロジックになるでしょう。この記事では未処理の例外が発生したことを知り、何かの処理を記述する方法を説明します。

AppDomain.UnhandledException

コンソールアプリケーションでは、未処理の例外が発生するとAppDomain.UnhandledExceptionイベントが発生します。

このイベントをハンドルして、ログ出力やメッセージ表示を行うことができます。

Module Module1

    Sub Main()

        AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf Application_Error

        Dim x As Char = ""(100) 'わざと例外を発生させます。

    End Sub

    Private Sub Application_Error(sender As Object, e As UnhandledExceptionEventArgs)

        Console.WriteLine("エラーが発生しました。アプリケーションを終了します。")

    End Sub

End Module
■リスト1:VB版 AppDomain.UnhandledExceptionで未処理の例外をキャッチする

class Program
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.UnhandledException += Application_UnhandledException;

        char x = ""[100]; //わざと例外を発生させます。
    }

    private static void Application_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine("エラーが発生しました。アプリケーションを終了します。");
    }
}
■リスト2:C#版 AppDomain.UnhandledExceptionで未処理の例外をキャッチする

Visual Studioでデバッグ実行していると、Visual Studioが例外の発生を検知して実行を止めてしまうので、この機能を実際に確認するにはデバッグなしで実行(Ctrl + F5)を行ってください。

アプリケーションの終了コードを指定するにはEnvironment.Exitメソッドでアプリケーションを終了させます。

なお、Application_UnhandledException内で発生した例外の情報は e.ExceptionObject から取得できます。

Windowsフォームアプリケーション

VBのWindowsフォームアプリケーションでは未処理の例外を簡単にキャッチできます。その方法は次の節「Visual BasicのMyApplication_UnhandledException」を参照してください。

C#のWindowsフォームアプリケーションで未処理の例外をキャッチするには次のようにします。

Application.ThreadException += Application_UnhandledException;
AppDomain.CurrentDomain.UnhandledException += Application_UnhandledException;
■リスト3:C#版 Windowsフォームアプリケーションで未処理の例外をキャッチする

この例では2種類のイベントはを同じApplication_UnhandledExceptionメソッドでハンドルするようにしているので、このメソッドの第二引数 e の型を Exceptionにします。

private void Application_UnhandledException(object sender, EventArgs e)
{
    //ここに処理を書く
}
■リスト4:

2つのイベントのハンドラーを分けて型をより厳密に書くこともできます。

このイベントが呼び出された場合、アプリケーションの状況は予期せぬ状況になっていますので処理を続行することは危険です。Environment.Exitメソッドなどでアプリケーションを終了させるプログラムを書いてください。

Visual BasicのMyApplication_UnhandledException

Visual BasicでWindowsフォームアプリケーションを作成すると独自のアプリケーションフレームワーク機能により、アプリケーションイベントと呼ばれる一連のイベントを簡単に使用できます。この中にUnhandledExceptionイベントがあり、未処理の例外が発生した場合に呼び出されます。

このUnhandledExceptionイベントを使用するにはソリューションエクスプローラーでプロジェクトのMy Projectで、アプリケーションページの下の方にある「アプリケーション イベントの表示」をクリックします。

ApplicationEvents.vbファイルが作成されるので、そのファイルに次のように記述します。

Imports Microsoft.VisualBasic.ApplicationServices

Namespace My
    Partial Friend Class MyApplication
        Private Sub MyApplication_UnhandledException(sender As Object, e As UnhandledExceptionEventArgsHandles Me.UnhandledException

            MsgBox("エラーが発生しました。アプリケーションを終了します。")
        End Sub
    End Class
End Namespace
■リスト5:VB版 AppDomain.UnhandledExceptionで未処理の例外をキャッチする

この機能も実際に試すにはデバッグなしで実行(Ctrl + F5)を行ってください。

発生した例外の情報は e.Exceptionで取得できます。

C#にはこの機能はありませんので、AppDomain.UnhandledExceptionイベントを使用してください。VBではどちらも使用できます。

ASP.NETの場合

ASP.NETで未処理の例外をキャッチするにはGlobal.asaxのApplication_Errorを使用します。 Global.asaxについてはこちらの記事を参照してください。

ASP.NETはIISなどのWebサーバーでホストされることを前提したフレームワークです。Application_Errorはこのフレームワークの中で適切なエラー処理のタイミングを提供しています。

下記はGlobal.asax内に記述することを前提に未処理の例外をキャッチする例です。

void Application_Error(object sender, EventArgs e)
{
    Server.ClearError();
    Response.Clear();
    Response.Write("エラーが発生しました。アプリケーションを終了します。");
}
■リスト6:C#版 ASP.NETで未処理の例外をキャッチする

この例を試すにはデバッグなしで実行(Ctrl + F5)をしてください。

この例では、レスポンスを返すように記述しているため、Server.ClearErrorの呼び出しが必要です。この呼び出しがないと、クライアントにはここで設定したレスポンスは返らずASP.NETのパイプラインが通常の例外処理で生成するレスポンスが返ります。

発生した例外の情報を取得するには Server.GetLastErrorメソッドを使用します。

また、ASP.NETでは、このApplication_Errorの他にweb.configのcustomErrorsで例外発生時の動作をある程度制御することもできます。Application_Errorに書いたことと違うことが起こるようでしたらcustomErrorsの設定も確認してみてください。