2010-09-20 30 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做
相關問題