2010-09-20 26 views
31

我正在使用Windows窗体应用程序,并使用System.Timers.Timer来定期检查数据库中的数据。如何获取Timer Elapsed事件中发生的异常?

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

回答

22

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

MSDN

在.NET Framework 2.0版和 早些时候,Timer组件抓住 和抑制由事件处理程序针对逝去 事件抛出 所有异常。此行为受.NET 框架将来版本中的 更改影响。

刚刚在.NET 4.0中签入,并且此行为尚未更改。

+1

代码示例请问? – hrh 2012-04-25 16:31:03

+0

我想我得到它,我将异常传递给我的主线程上的函数,然后该函数在抛出异常之前在函数中使用this.Invoke()。我是否正确理解这一点? – hrh 2012-04-25 16:41:43

+0

是否有任何新的方法来捕获.net 4.5的意外错误?它仍然吞咽,并不是无论如何记录错误没有包装整个_timer_Elapsed里面试试catch? – MonsterMMORPG 2014-08-21 13:02:49

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

如果您没有访问到主线程,可以抛出另一个异常,非-timer螺纹:

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

不错。这将保留堆栈跟踪并将异常泵入AppDomain.UnhandledException。谢谢! – Nathan 2011-10-10 20:14:09

+0

我有一个无限循环使用这种方法。抛出异常并且总是通过'AppDomain.UnhandledException'处理。我怎样才能避免这种情况? – anmarti 2013-09-13 11:36:55

+0

太好了。非常感谢。 – 2014-03-20 13:46:58

2

我猜你要处理的主要形式外,该解决方案是不完整的,但显示了如何用“行动”

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

} 
0123做
相关问题