方法: 初回例外通知を受け取る
Note
この記事は .NET Framework に固有のものです。 .NET 6 以降のバージョンを含め、.NET の新しい実装には適用されません。
AppDomain クラスの FirstChanceExceptionイベントを使用すると、共通言語ランタイムが例外ハンドラーの検索を開始する前に、例外がスローされたことを知らせる通知を受け取ることができます。
このイベントは、アプリケーション ドメイン レベルで発生します。 実行スレッドは複数のアプリケーション ドメインを通過する可能性があるため、あるアプリケーション ドメインでハンドルされない例外が別のアプリケーション ドメインでハンドルされることもあります。 通知は、イベントのハンドラーを追加した各アプリケーション ドメインで発生し、いずれかのアプリケーション ドメインで例外がハンドルされるまで続行されます。
ここで紹介するプロシージャと例では、1 つのアプリケーション ドメインを実装する単純なプログラムで初回例外通知を受け取る方法と、作成したアプリケーション ドメインで初回例外通知を受け取る方法について説明します。
複数のアプリケーション ドメインにわたる複雑な例については、FirstChanceException イベントの例を参照してください。
既定のアプリケーション ドメインで初回例外通知を受け取る
次のプロシージャでは、アプリケーションのエントリ ポイントである Main()
メソッドが既定のアプリケーション ドメインで実行されます。
既定のアプリケーション ドメインで初回例外通知の動作を確認するには
ラムダ関数を使用して FirstChanceException イベントのイベント ハンドラーを定義し、それをイベントにアタッチします。 この例では、イベント ハンドラーによって、イベントが処理されたアプリケーション ドメインの名前と、例外の Message プロパティを出力します。
using System; using System.Runtime.ExceptionServices; class Example { static void Main() { AppDomain.CurrentDomain.FirstChanceException += (object source, FirstChanceExceptionEventArgs e) => { Console.WriteLine("FirstChanceException event raised in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, e.Exception.Message); };
Imports System.Runtime.ExceptionServices Class Example Shared Sub Main() AddHandler AppDomain.CurrentDomain.FirstChanceException, Sub(source As Object, e As FirstChanceExceptionEventArgs) Console.WriteLine("FirstChanceException event raised in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, e.Exception.Message) End Sub
例外をスローし、それをキャッチします。 ランタイムが例外ハンドラーを見つける前に、FirstChanceException イベントが発生し、メッセージが表示されます。 このメッセージの後に、例外ハンドラーによるメッセージが表示されます。
try { throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); } catch (ArgumentException ex) { Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message); }
Try Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName) Catch ex As ArgumentException Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message) End Try
例外をスローしますが、それをキャッチしません。 ランタイムが例外ハンドラーを検索する前に、FirstChanceException イベントが発生し、メッセージが表示されます。 例外ハンドラーがないため、アプリケーションは終了します。
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); } }
Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName) End Sub End Class
このプロシージャの最初の 3 つのステップに示されているコードは、完全なコンソール アプリケーションを形成します。 既定のアプリケーション ドメインの名前は .exe ファイルの名前と拡張子から構成されるため、アプリケーションからの出力は .exe ファイルの名前によって異なります。 次のサンプル出力を参照してください。
/* This example produces output similar to the following: FirstChanceException event raised in Example.exe: Thrown in Example.exe ArgumentException caught in Example.exe: Thrown in Example.exe FirstChanceException event raised in Example.exe: Thrown in Example.exe Unhandled Exception: System.ArgumentException: Thrown in Example.exe at Example.Main() */
' This example produces output similar to the following: ' 'FirstChanceException event raised in Example.exe: Thrown in Example.exe 'ArgumentException caught in Example.exe: Thrown in Example.exe 'FirstChanceException event raised in Example.exe: Thrown in Example.exe ' 'Unhandled Exception: System.ArgumentException: Thrown in Example.exe ' at Example.Main()
別のアプリケーション ドメインで初回例外通知を受け取る
プログラムに複数のアプリケーション ドメインが含まれている場合は、通知を受け取るアプリケーション ドメインを選択できます。
作成したアプリケーション ドメインで初回例外通知を受け取るには
FirstChanceException イベントのイベント ハンドラーを定義します。 この例では、
static
メソッド (Visual Basic ではShared
メソッド) を使用して、イベントが処理されたアプリケーション ドメインの名前と、例外の Message プロパティを出力します。static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e) { Console.WriteLine("FirstChanceException event raised in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, e.Exception.Message); }
Shared Sub FirstChanceHandler(ByVal source As Object, ByVal e As FirstChanceExceptionEventArgs) Console.WriteLine("FirstChanceException event raised in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, e.Exception.Message) End Sub
アプリケーション ドメインを作成し、そのアプリケーション ドメインの FirstChanceException イベントにイベント ハンドラーを追加します。 この例では、アプリケーション ドメインの名前は
AD1
です。AppDomain ad = AppDomain.CreateDomain("AD1"); ad.FirstChanceException += FirstChanceHandler;
Dim ad As AppDomain = AppDomain.CreateDomain("AD1") AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler
既定のアプリケーション ドメインでも、同じようにこのイベントを処理できます。 既定のアプリケーション ドメインへの参照を取得するには、
static
(Visual Basic ではShared
) AppDomain.CurrentDomain プロパティをMain()
で使用します。
アプリケーション ドメインで初回例外通知の動作を確認するには
前のプロシージャで作成したアプリケーション ドメインに
Worker
オブジェクトを作成します。Worker
クラスは、パブリックで、MarshalByRefObject から派生する必要があります。この記事の最後にある完全な例を参照してください。Worker w = (Worker) ad.CreateInstanceAndUnwrap( typeof(Worker).Assembly.FullName, "Worker");
Dim w As Worker = CType(ad.CreateInstanceAndUnwrap( GetType(Worker).Assembly.FullName, "Worker"), Worker)
例外をスローする
Worker
オブジェクトのメソッドを呼び出します。 この例では、Thrower
メソッドが 2 回呼び出されます。 1 回目のメソッド引数はtrue
であるため、メソッドは自身の例外をキャッチします。 2 回目の引数はfalse
です。この場合、Main()
メソッドが既定のアプリケーション ドメインで例外をキャッチします。// The worker throws an exception and catches it. w.Thrower(true); try { // The worker throws an exception and doesn't catch it. w.Thrower(false); } catch (ArgumentException ex) { Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message); }
' The worker throws an exception and catches it. w.Thrower(true) Try ' The worker throws an exception and doesn't catch it. w.Thrower(false) Catch ex As ArgumentException Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message) End Try
Thrower
メソッドにコードを追加して、メソッドが自身の例外をハンドルするかどうかを制御します。if (catchException) { try { throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); } catch (ArgumentException ex) { Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message); } } else { throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); }
If catchException Try Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName) Catch ex As ArgumentException Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message) End Try Else Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName) End If
例
次の例では、AD1
という名前のアプリケーション ドメインを作成し、このアプリケーション ドメインの FirstChanceException イベントにイベント ハンドラーを追加します。 この例では、アプリケーション ドメインに Worker
クラスのインスタンスを作成し、Thrower
という名前のメソッドを呼び出します。このメソッドにより、ArgumentExceptionがスローされます。 メソッドは、引数の値に応じて、例外をキャッチするか、例外のハンドルに失敗します。
Thrower
メソッドが AD1
で例外をスローするたびに、AD1
で FirstChanceException イベントが発生し、イベント ハンドラーによりメッセージが表示されます。 次に、ランタイムによって例外ハンドラーが検索されます。 最初のケースでは、例外ハンドラーは AD1
で見つかります。 2 番目のケースでは、例外は AD1
でハンドルされず、代わりに既定のアプリケーション ドメインでキャッチされます。
Note
既定のアプリケーション ドメインの名前は、実行可能ファイルの名前と同じです。
既定のアプリケーション ドメインに FirstChanceException イベントのハンドラーを追加すると、既定のアプリケーション ドメインが例外をハンドルする前に、イベントが発生して処理されます。 これを確認するには、Main()
の先頭に C# コード AppDomain.CurrentDomain.FirstChanceException += FirstChanceException;
(Visual Basic では AddHandler AppDomain.CurrentDomain.FirstChanceException, FirstChanceException
) を追加します。
using System;
using System.Reflection;
using System.Runtime.ExceptionServices;
class Example
{
static void Main()
{
// To receive first chance notifications of exceptions in
// an application domain, handle the FirstChanceException
// event in that application domain.
AppDomain ad = AppDomain.CreateDomain("AD1");
ad.FirstChanceException += FirstChanceHandler;
// Create a worker object in the application domain.
Worker w = (Worker) ad.CreateInstanceAndUnwrap(
typeof(Worker).Assembly.FullName, "Worker");
// The worker throws an exception and catches it.
w.Thrower(true);
try
{
// The worker throws an exception and doesn't catch it.
w.Thrower(false);
}
catch (ArgumentException ex)
{
Console.WriteLine("ArgumentException caught in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, ex.Message);
}
}
static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
{
Console.WriteLine("FirstChanceException event raised in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
}
}
public class Worker : MarshalByRefObject
{
public void Thrower(bool catchException)
{
if (catchException)
{
try
{
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
}
catch (ArgumentException ex)
{
Console.WriteLine("ArgumentException caught in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, ex.Message);
}
}
else
{
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
}
}
}
/* This example produces output similar to the following:
FirstChanceException event raised in AD1: Thrown in AD1
ArgumentException caught in AD1: Thrown in AD1
FirstChanceException event raised in AD1: Thrown in AD1
ArgumentException caught in Example.exe: Thrown in AD1
*/
Imports System.Reflection
Imports System.Runtime.ExceptionServices
Class Example
Shared Sub Main()
' To receive first chance notifications of exceptions in
' an application domain, handle the FirstChanceException
' event in that application domain.
Dim ad As AppDomain = AppDomain.CreateDomain("AD1")
AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler
' Create a worker object in the application domain.
Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
GetType(Worker).Assembly.FullName, "Worker"),
Worker)
' The worker throws an exception and catches it.
w.Thrower(true)
Try
' The worker throws an exception and doesn't catch it.
w.Thrower(false)
Catch ex As ArgumentException
Console.WriteLine("ArgumentException caught in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, ex.Message)
End Try
End Sub
Shared Sub FirstChanceHandler(ByVal source As Object,
ByVal e As FirstChanceExceptionEventArgs)
Console.WriteLine("FirstChanceException event raised in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, e.Exception.Message)
End Sub
End Class
Public Class Worker
Inherits MarshalByRefObject
Public Sub Thrower(ByVal catchException As Boolean)
If catchException
Try
Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
Catch ex As ArgumentException
Console.WriteLine("ArgumentException caught in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, ex.Message)
End Try
Else
Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
End If
End Sub
End Class
' This example produces output similar to the following:
'
'FirstChanceException event raised in AD1: Thrown in AD1
'ArgumentException caught in AD1: Thrown in AD1
'FirstChanceException event raised in AD1: Thrown in AD1
'ArgumentException caught in Example.exe: Thrown in AD1
関連項目
.NET