web-dev-qa-db-ja.com

Timer Elapsedイベントで発生する例外を取得するにはどうすればよいですか?

私は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);
        }
    }
35
Clack

メインスレッドにアクセスできない場合は、タイマー以外の別のスレッドで例外をスローできます。

catch (Exception exception)
{
    ThreadPool.QueueUserWorkItem(
        _ => { throw new Exception("Exception on timer.", exception); });
}
32
svick

System.Timers.Timerは、イベントハンドラーでスローされた例外をすべて飲み込むため、例外を別のスレッド(おそらくUIスレッド)にマーシャリングする必要があります。これは、Control.Invokeを介して、またはエラー情報をメンバー変数に格納し、操作の完了後にUIスレッドにこのエラー情報をチェックさせることによって行うことができます。 null以外の場合、UIはスローする可能性があります。

から [〜#〜] msdn [〜#〜]

.NET Frameworkバージョン2.0以前では、Timerコンポーネントは、Elapsedイベントのイベントハンドラーによってスローされたすべての例外をキャッチして抑制します。この動作は、.NETFrameworkの将来のリリースで変更される可能性があります。

.NET 4.0をチェックインしたばかりで、この動作はまだ変更されていません。

25
Kent Boogaart

例外をローカル変数に割り当てて、例外がスローされたかどうかを確認できます。

// 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;
    }
4
Koekiebox

メインフォームで例外を処理したいと思います。このソリューションは完全ではありませんが、「アクション」を使用して処理する方法を示しています。

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);
        }
    }

}
2