いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

例外発生時catchブロックよりも先に例外通知を受ける。 (.NET 4.0, AppDomain, FirstChanceException, System.Runtime.ExceptionServices)


知ってると、ちょっと便利かもしれないTips。メモメモ。
この方法は、.NET 4.0から可能です。


.NET 4.0より、AppDomainクラスに以下のイベントが追加されました。

public event EventHandler<FirstChanceExceptionEventArgs> FirstChanceException


このイベントは、アプリケーションドメイン内で例外が発生した際に最初に通知されるイベントです。
通知されるタイミングは、コード上のcatchブロックよりも先となります。まさにファーストチャンスの名前通りです。


このイベントは、通知のみのイベントとなっており、イベントをハンドルしたからといって例外の伝播が止まるわけでは
ありません。このイベントで処理した後でも通常通り例外はコード上で発生します。また、このイベントは
アプリケーションドメイン毎に設定可能です。


以下、サンプルです。

  #region AppDomainSamples-01
  /// <summary>
  /// AppDomainクラスのサンプルです。
  /// </summary>
  public class AppDomainSamples01 : IExecutable
  {
    public void Execute()
    {
      //
      // AppDomainには、.NET 4.0より以下のイベントが追加されている。
      //   ・FirstChanceExceptionイベント
      // このイベントは、例外が発生した際に文字通り最初に通知されるイベントである。
      // このイベントに通知されるタイミングは、catch節にて例外が補足されるよりも先となる。
      // 
      // 注意点として
      //   ・このイベントは、通知のみとなる。このイベントをハンドルしたからといって例外の発生が
      //    ここで止まるわけではない。例外は通常通りプログラムコード上のcatchに入ってくる。
      //   ・このイベントは、アプリケーションドメイン毎に定義できる。
      //   ・FirstChanceExceptionイベント内での例外は、絶対にハンドラ内でキャッチしないといけない。
      //    そうしないと、再帰的にFirstChanceExceptionが発生する。
      //   ・イベント引数であるFirstChanceExceptionEventArgsクラスは
      //    System.Runtime.ExceptionServices名前空間に存在する。
      //
      
      // 基底のAppDomainにて、FirstChanceExceptionイベントをハンドル.
      AppDomain.CurrentDomain.FirstChanceException += FirstChanceExHandler;

      try
      {
        // わざと例外発生.
        throw new InvalidOperationException("test Ex messsage");
      } 
      catch (InvalidOperationException ex)
      {
        // 本来のcatch処理.
        Console.WriteLine("Catch clause: {0}", ex.Message);
      }
      
      // イベントをアンバインド.
      AppDomain.CurrentDomain.FirstChanceException -= FirstChanceExHandler;
    }
    
    // イベントハンドラ.
    void FirstChanceExHandler(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
    {
      Console.WriteLine("FirstChanceException: {0}", e.Exception.Message);
    }
  }
  #endregion


実行結果は、以下になります。

  FirstChanceException: test Ex messsage
  Catch clause: test Ex messsage


catchブロックよりも先にイベントが発生していることが分かります。
あと、ちょっとした注意点ですがFirstChanceExceptionEventArgsクラスは

System.Runtime.ExceptionServices

という、通常using指定していないだろう名前空間にいますので、忘れずにusingしましょう。


以下、参考情報です。

================================
過去の記事については、以下のページからご参照下さい。