2010-09-20 11 views
31

Pracuję z aplikacją Windows Forms i hava z klasą menedżera, która używa System.Timers.Timer do okresowego sprawdzania danych z bazy danych.Jak uzyskać wyjątek, który ma miejsce w zdarzeniu, które upłynęło w czasie?

Jak uzyskać wyjątek, który występuje w czasomierzu, który został dostarczony do głównej aplikacji? Jeśli korzystam z poniższego kodu, wyjątek get jest "połknięty", a główna aplikacja nigdy go nie pobiera (nawet jeśli mam procedury obsługi wyjątków ThreadException i 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); 
     } 
    } 

Odpowiedz

22

Od System.Timers.Timer jaskółki żadnego wyjątku wrzucony obsługi zdarzeń, trzeba będzie zebrać wyjątek do innego wątku (prawdopodobnie wątku UI). Można to zrobić za pomocą Control.Invoke lub zapisując informacje o błędzie w zmiennej członkowskiej i mając wątek interfejsu użytkownika sprawdzać te informacje o błędzie po zakończeniu operacji. Jeśli nie jest to null, interfejs może wtedy wyrzucić.

Od MSDN:

W wersji .NET Framework 2.0 i wcześniej, komponent czasowy łapie i tłumi wszelkie wyjątki generowane przez obsługi zdarzeń dla zdarzenia Upływający . To zachowanie podlega zmianie w przyszłych wydaniach .NET Framework.

Właśnie sprawdzono .NET 4.0, a to zachowanie jeszcze się nie zmieniło.

+1

Kod Przykład Proszę? – hrh

+0

Myślę, że rozumiem, przekazałem wyjątek funkcji w moim głównym wątku, a następnie funkcja ta użyła this.Invoke() na funkcji przed wyrzuceniem wyjątku. Czy rozumiem to poprawnie? – hrh

+0

Czy istnieje jakaś nowa metoda przechwytywania nieoczekiwanych błędów w .net 4.5? Nadal połyka i nie ma w ogóle logów błędów bez owijania całego _timer_Elapsed inside try catch? – MonsterMMORPG

4

można przypisać wyjątku do zmiennej lokalnej i sprawdzić, czy wyjątek został rzucony:

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

Jeśli nie masz dostępu do głównego wątku, można rzucić wyjątek na inny, niż -timer wątek:

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

Nice. Zachowuje to śledzenie stosu i pompuje wyjątek do AppDomain.UnhandledException. Dziękuję Ci! – Nathan

+0

Mam nieskończoną pętlę przy użyciu tego podejścia. Wyjątek jest zawsze generowany i odrzucany przez wyjątek 'AppDomain.UnhandledException'. Jak mogę tego uniknąć? – anmarti

+0

Świetnie. Wielkie dzięki. –

2

Chyba, że ​​chcesz obsłużyć wyjątek na głównej postaci, to rozwiązanie nie jest kompletna, ale pokazuje, jak to zrobić z „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); 
     } 
    } 

} 
Powiązane problemy