如何获得Timer Elapsed事件中发生的异常?

时间:2010-09-20 08:35:01

标签: c# multithreading timer

我正在使用Windows窗体应用程序,并且使用System.Timers.Timer来定期检查数据库中的数据。

如何将计时器Elapsed事件处理程序中发生的异常传递到主应用程序中?如果我使用下面的代码,异常会被“吞噬”,主应用程序永远不会得到它(即使我有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);
        }
    }

4 个答案:

答案 0 :(得分:30)

如果您无权访问主线程,则可以将异常抛出到另一个非计时器线程上:

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

答案 1 :(得分:25)

由于System.Timers.Timer吞下了事件处理程序中抛出的任何异常,因此您需要将异常编组到另一个线程(可能是UI线程)。您可以通过Control.Invoke执行此操作,或者将错误信息存储在成员变量中,并让UI线程在操作完成后检查此错误信息。如果不是null,那么UI就可以抛出。

来自MSDN

  

在.NET Framework 2.0版和   之前,Timer组件捕获   并抑制抛出的所有异常   由Elapsed的事件处理程序   事件。此行为受制于   在将来的.NET版本中进行更改   框架。

刚刚在.NET 4.0中检查过,此行为尚未更改。

答案 2 :(得分:4)

您可以将异常分配给局部变量并检查是否抛出了异常:

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

答案 3 :(得分:2)

我想你想要在主窗体上处理异常,这个解决方案不完整,但是展示了如何用“Action”来实现它

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

}