Jaka jest różnica między Application.ThreadException i AppDomain.CurrentDomain.UnhandledException?

107

W porządku, to jest łatwe:

  • Jaka jest różnica między Application.ThreadExceptioni
    AppDomain.CurrentDomain.UnhandledException?

  • Czy muszę obsługiwać oba?

Dzięki!

JohnIdol
źródło

Odpowiedzi:

98

Application.ThreadException jest specyficzny dla Windows Forms. Winforms uruchamia programy obsługi zdarzeń w odpowiedzi na komunikaty wysyłane do niego przez system Windows. Na przykład wydarzenie Click, jestem pewien, że je znasz. Jeśli taka procedura obsługi zdarzeń zgłasza wyjątek, w pętli komunikatów Winforms znajduje się zatrzymanie wstecz, które przechwytuje ten wyjątek.

Ten mechanizm awaryjny uruchamia zdarzenie Application.ThreadException . Jeśli go nie zastąpisz, użytkownik otrzyma ThreadExceptionDialog . Dzięki temu może zignorować wyjątek i kontynuować działanie programu. Przy okazji nie jest to świetny pomysł.

Możesz wyłączyć to zachowanie, wywołując Application.SetUnhandledExceptionMode () w metodzie Main () w Program.cs. Bez tego backstopu normalna rzecz dzieje się, gdy wątek umiera z powodu nieobsługiwanego wyjątku: zostaje wyzwolony AppDomain.UnhandledException i program się kończy.

Fwiw: „ThreadException” był bardzo złym wyborem nazwy. Nie ma to nic wspólnego z wątkami.

Hans Passant
źródło
I jak zatrzymać awarię aplikacji WinForms przy wystąpieniu Application.ThreadException. Zadałem pytanie w związku z tym [tutaj ] z moim małym kodem C #.
Mahesha999
2
Zawsze czytam to jako wyjątek wątku aplikacji, biorąc pod uwagę, że winForms jest powiązany z pojedynczym wątkiem.
Gusdor
36

Ze źródła :

W aplikacjach korzystających z Windows Forms nieobsłużone wyjątki w głównym wątku aplikacji powodują zgłoszenie Application.ThreadException zdarzenia. Jeśli to zdarzenie jest obsługiwane, domyślne zachowanie polega na tym, że nieobsługiwany wyjątek nie powoduje zakończenia aplikacji, mimo że aplikacja pozostaje w nieznanym stanie. W takim przypadku UnhandledException zdarzenie nie jest wywoływane. To zachowanie można zmienić przy użyciu pliku konfiguracyjnego aplikacji lub przy użyciu Application.SetUnhandledExceptionModemetody zmiany trybu UnhandledExceptionMode.ThrowExceptionprzed ThreadException podłączeniem programu obsługi zdarzeń. Dotyczy to tylko głównego wątku aplikacji. UnhandledException Zdarzenie jest wywoływane za nieobsłużonych wyjątków rzucanych w innych wątkach.

Począwszy od programu Visual Studio 2005 , struktura aplikacji Visual Basic udostępnia inne zdarzenie dla nieobsłużonych wyjątków w głównym wątku aplikacji - WindowsFormsApplicationBase.UnhandledException. To zdarzenie ma obiekt argumentów zdarzenia o tej samej nazwie, co obiekt argumentów zdarzenia używany przez AppDomain.UnhandledException, ale z innymi właściwościami. W szczególności ten obiekt argumentów zdarzenia ma ExitApplicationwłaściwość, która umożliwia kontynuowanie działania aplikacji, ignorując nieobsługiwany wyjątek (i pozostawiając aplikację w nieznanym stanie). W takim przypadku zdarzenie AppDomain.UnhandledException nie zostanie zgłoszone.

Application.ThreadExceptionmoże zostać przechwycony, a aplikacja mogłaby kontynuować (generalnie nie jest to świetny pomysł, ale w przypadku aplikacji, takich jak okresowe uruchamianie niektórych akcji, jest to dobre rozwiązanie).

Aby przechwytywać wyjątki, które występują w wątkach, które nie zostały utworzone i nie należą do Windows Forms, użyj AppDomain.UnhandledException. Umożliwia aplikacji rejestrowanie informacji o wyjątku, zanim domyślny program obsługi systemu zgłosi wyjątek użytkownikowi i zakończy działanie aplikacji.
Obsługa tego wyjątku nie zapobiega zamknięciu aplikacji.
Maksymalnym możliwym działaniem (dane programu mogą ulec uszkodzeniu, gdy wyjątki nie są obsługiwane) jest zapisanie danych programu do późniejszego odtworzenia. Następnie domena aplikacji jest zwalniana, a aplikacja kończy się.

Począwszy od platformy .NET 4 , to zdarzenie nie jest zgłaszane w przypadku wyjątków, które uszkadzają stan procesu, takich jak przepełnienia stosu lub naruszenia dostępu, chyba że program obsługi zdarzeń jest krytyczny dla bezpieczeństwa i ma HandleProcessCorruptedStateExceptionsAttribute atrybut.

Aby uzyskać więcej informacji, zobacz MSDN .

serhio
źródło
18

OK - miałem to przed sobą, ten fragment kodu z msdn jest dość oczywisty:

public static void Main(string[] args)
{
    // Add the event handler for handling UI thread exceptions to the event.
    Application.ThreadException += new 
        ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);

    // Set the unhandled exception mode to force all Windows Forms 
    // errors to go through our handler.
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

    // Add the event handler for handling non-UI thread exceptions to the event. 
    AppDomain.CurrentDomain.UnhandledException +=
        new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

    // Runs the application.
    Application.Run(new ErrorHandlerForm());
}
JohnIdol
źródło
3
kontrastuje to z inną odpowiedzią serhio, gdy mówi: UnhandledExceptionMode.ThrowException należy ustawić przed podłączeniem obsługi zdarzenia ThreadException. Nie jestem pewien, czy kolejność naprawdę ma znaczenie ...
Davide Piras,
@DavidePiras tak, i jest coś bardziej mętnego. Wydaje się, że SetUnhandledException nie robi różnicy w moim przypadku.
nawfal,
0

Rzecz w tym, że ThreadExceptionwystępuje z powodu problemu z twoim wątkiem, Unhandled Exceptionjest uruchamiany, jeśli kod zgłasza wyjątek, który nie jest obsługiwany.

Najłatwiejszym sposobem spowodowania drugiego jest utworzenie aplikacji bez bloków try ... catch i zgłoszenie wyjątku.

Teraz, jeśli potrzebujesz ubezpieczenia, możesz sobie z nimi poradzić, jednak jeśli złapiesz i obsłużysz exceptionspoprawnie, nie powinieneś potrzebować przewodnika, UnhandledExceptionponieważ jest to trochę jak złapanie wszystkiego.

Joshua Cauble
źródło
dzięki - to, czego nie byłem zbyt jasny, to jeśli obsługując UnhandledException złapałbym również ThreadException - co wydaje się nie mieć miejsca
JohnIdol