私はWindowsフォームアプリケーションを使用していて、System.Timers.Timerを使用してデータベースからのデータを定期的にチェックするマネージャークラスを持っています。
メインアプリケーションに配信されたタイマー経過イベントハンドラーで発生する例外を取得するにはどうすればよいですか?以下のコードを使用している場合、例外は「飲み込まれ」、メインアプリケーションはそれを取得しません(ThreadExceptionとUnHandledExceptionのハンドラーがある場合でも)。
// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Manager class
private System.Timers.Timer _timer;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
throw new ApplicationException("How do I get this error back into main thread...", ex);
}
}
メインスレッドにアクセスできない場合は、タイマー以外の別のスレッドで例外をスローできます。
catch (Exception exception)
{
ThreadPool.QueueUserWorkItem(
_ => { throw new Exception("Exception on timer.", exception); });
}
System.Timers.Timer
は、イベントハンドラーでスローされた例外をすべて飲み込むため、例外を別のスレッド(おそらくUIスレッド)にマーシャリングする必要があります。これは、Control.Invoke
を介して、またはエラー情報をメンバー変数に格納し、操作の完了後にUIスレッドにこのエラー情報をチェックさせることによって行うことができます。 null
以外の場合、UIはスローする可能性があります。
から [〜#〜] msdn [〜#〜] :
.NET Frameworkバージョン2.0以前では、Timerコンポーネントは、Elapsedイベントのイベントハンドラーによってスローされたすべての例外をキャッチして抑制します。この動作は、.NETFrameworkの将来のリリースで変更される可能性があります。
.NET 4.0をチェックインしたばかりで、この動作はまだ変更されていません。
例外をローカル変数に割り当てて、例外がスローされたかどうかを確認できます。
// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Manager class
private System.Timers.Timer _timer;
private exception = null;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
//reset the exception in case object is reused.
this.exception = null;
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
this.exception = ex;
}
}
/**
* Checks whether the exception object is set.
*/
public bool hasExceptionOccured(){
return (this.exception != null);
}
//The main application will call this to get the exception.
public Exception getException(){
return this.exception;
}
メインフォームで例外を処理したいと思います。このソリューションは完全ではありませんが、「アクション」を使用して処理する方法を示しています。
using System;
using System.Timers;
public class MainForm
{
public MainForm()
{
var tm = new TestManager(exception =>
{
//do somthing with exception
//note you are still on the timer event thread
});
}
}
public class TestManager
{
private readonly Action<Exception> _onException;
public TestManager(System.Action<System.Exception> onException )
{
_onException = onException;
}
private System.Timers.Timer _timer;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
//throw new ApplicationException("How do I get this error back into main thread...", ex);
_onException(ex);
}
}
}