バックグラウンド ワーカーを使用していますが、RunWorkerCompleted イベント ハンドラーで発生した新しい例外が Application.ThreadException ハンドラーに表示されないことがわかりました。例: Program.cs のどこか:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += delegate(object o, ThreadExceptionEventArgs args)
{
if (args.Exception != null)
Console.WriteLine("thread error {0}", args.Exception.Message);
};
Application.Run(new Form1());
}
次に、ボタンをクリックします(テスト目的のみ)
var bw = new BackgroundWorker();
bw.DoWork += delegate(object o, DoWorkEventArgs args) { /* some calculations here */ };
bw.RunWorkerCompleted += delegate(object sender1, RunWorkerCompletedEventArgs eventArgs)
{
try
{
//in run worker completed exception occurs
throw new ApplicationException("test exception 1");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("throwing new exception");
throw new ApplicationException(string.Format("catched '{0}'", ex.Message), ex);
}
};
bw.RunWorkerAsync();
プログラムの出力は次のとおりです。
テスト例外 1
新しい例外を投げる
スレッド エラー テスト例外 1
私は Application.ThreadException ハンドラー例外で、元の例外ではなく、テキストスレッドエラーがキャッチされた「テスト例外1」が表示されるはずだと信じています。
私を助けていただけますか - なぜそれが起こるのか、どうすれば解決できるのでしょうか? これはサンプルコードです。実際のコードでは、RunWorkerCompleted ハンドラー内にネストされたメソッドがいくつかあります。そして、それらのメソッドのいくつかは、例外をキャッチし、内部例外に追加情報と元の例外を追加して新しいものをスローします。したがって、 Application.ThreadException ハンドラーでは、スローされた元の例外だけでなく、チェーン全体も取得したいと考えています。
ありがとうございました
ボタンクリックによる未処理の例外に対して GetBaseException が呼び出されないことがわかりました(たとえば)
以下のように、Program.Main メソッドに TreadException イベント ハンドラがあるとします。
Application.ThreadException += (o, args) =>
{
Console.WriteLine("BEGIN ThreadException handler");
ShowException(args.Exception);
Console.WriteLine("END ThreadException handler\r\n");
};
および Program.ShowException メソッドは次のようになります。
static void ShowException(Exception ex)
{
var tab = "";
while (ex != null)
{
Console.WriteLine("{1}error '{0}'", ex.Message, tab);
tab += '\t';
ex = ex.InnerException;
}
}
コードの場合
try
{
throw new ApplicationException("button click 1");
}
catch (Exception ex)
{
throw new ApplicationException(string.Format("BC caught '{0}'", ex.Message), ex);
}
ボタンクリックで実行されると、次の出力が生成されます。
BEGIN ThreadException ハンドラー
エラー 'BC が 'ボタン クリック 1'' をキャッチしました
- エラー「ボタンクリック 1」*
END ThreadException ハンドラー
ご覧のとおり、例外チェーン全体が利用可能です。
ただし、ThreadException ハンドラーは、RunWorkerCompleted イベント ハンドラーで非常によく似たコードの元の例外のみを表示します (以下のコードはボタン クリック イベントで実行されました)。
var bw = new BackgroundWorker();
bw.DoWork += delegate(object o, DoWorkEventArgs args)
{
/* some calculations here */
};
bw.RunWorkerCompleted += delegate(object sender1, RunWorkerCompletedEventArgs eventArgs)
{
try
{
//in run worker completed exception occurs
Console.WriteLine("RWC exception test, throwing");
throw new ApplicationException("test exception 1");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("RWC got exception, throwing new");
throw new ApplicationException(string.Format("RWC caught '{0}'", ex.Message), ex);
}
};
bw.RunWorkerAsync();
出力は以下のとおりです。
RWC 例外テスト、スロー
テスト例外 1
RWC で例外が発生し、新しいものがスローされました
BEGIN ThreadException ハンドラー
error 'test exception 1' -- 元の例外のみ
END ThreadException ハンドラー
GetBaseException は RunWorkerCompleted イベントに対してのみ実行されるようです。