2009-01-02 5 views
34

Ich wollte einen Handler für alle unerwarteten Ausnahmen festlegen, die ich möglicherweise nicht in meinem Code gefangen hatte. In Program.Main() habe ich den folgenden Code:Umgang mit unbehandelten Ausnahmen Problem

AppDomain.CurrentDomain.UnhandledException 
    += new UnhandledExceptionEventHandler(ErrorHandler.HandleException); 

Aber es hat nicht funktioniert, wie ich erwartet hatte. Als ich die Anwendung im Debugging-Modus gestartet und eine Ausnahme ausgelöst habe, hat sie den Handler aufgerufen, aber danach ist der Ausnahme-Helper in Visual Studio aufgetaucht, als ob die Ausnahme ohne jegliche Behandlung aufgetreten wäre. Ich habe versucht, Application.Exit() innerhalb des Handlers, aber es hat nicht so gut funktioniert.

Was ich erreichen möchte ist, dass die Ausnahme mit meinem Handler behandelt wird und dann die Anwendung gut schließt. Gibt es einen anderen Weg, oder verwende ich den obigen Code falsch?

Antwort

27

Dies liegt daran, dass Sie Visual Studio im Debug-Modus ausführen. Wenn Sie Ihre App an einem anderen Ort freigeben und installieren, wird nur Ihr globaler Ausnahme-Handler verarbeitet.

6

Beachten Sie, dass unbehandelte Ausnahmen immer noch ziemlich fatal sind; Sie können dies nur zum Loggen oder für eine vorschnelle Schließung verwenden. Weder das noch Application.ThreadException kann als eine globale Senke für Fehler verwendet werden.

Der bessere Ansatz ist es, die richtige Handhabung hinzuzufügen - zum Beispiel um Ihre gesamte Main() Logik. Beachten Sie, dass selbst dieser einige Ausnahmen nicht abfangen kann, wie Fehler beim Laden von Formularen (die besonders unangenehm werden - Sie können sie mit einem angehängten Debugger abfangen, aber nicht ohne).

+0

gut, ja, natürlich weiß ich das;) – agnieszka

+0

dann warum nicht in Main() fangen? –

+0

"Ich weiß, dass" war eine Antwort auf den Teil "Senke für Fehler". Ich wurde Versuch-Catch in Main unterrichtet ist eine Sache, die Sie nicht tun sollten. Allerdings muss ich ehrlich sagen, dass ich nicht weiß, warum es ein schlechter Ansatz wäre (natürlich, wenn ich alle Ausnahmen erwische, die ich innerhalb des Codes denken kann) – agnieszka

31

Normalerweise verwende ich so etwas, um alle unerwarteten Ausnahmen der obersten Ebene zu erfassen.

using System; 

static class Program 
{ 
    [STAThread] 
    static void Main(string[] argv) 
    { 
    try 
    { 
     AppDomain.CurrentDomain.UnhandledException += (sender,e) 
     => FatalExceptionObject(e.ExceptionObject); 

     Application.ThreadException += (sender,e) 
     => FatalExceptionHandler.Handle(e.Exception); 

     // whatever you need/want here 

     Application.Run(new MainWindow()); 
    } 
    catch (Exception huh) 
    { 
     FatalExceptionHandler.Handle(huh); 
    } 
    } 

    static void FatalExceptionObject(object exceptionObject) { 
    var huh = exceptionObject as Exception; 
    if (huh == null) { 
     huh = new NotSupportedException(
     "Unhandled exception doesn't derive from System.Exception: " 
     + exceptionObject.ToString() 
    ); 
    } 
    FatalExceptionHandler.Handle(huh); 
    } 
} 

Vielleicht ist es etwas, das Sie auch hilfreich finden? Dieser Hauptcode leitet alle drei Möglichkeiten zum Abfangen unerwarteter Ausnahmen der höchsten Ebene durch einen Methodenaufruf weiter. Alles, was Sie jetzt benötigen, ist eine statische Klasse FatalExceptionHandler, die Ihre Exception-Behandlung auf oberster Ebene in ihrer Handle-Methode enthält.

Und wirklich, jeder Anwendungsentwickler weiß, es gibt eigentlich nur zwei Dinge zu tun gibt:

  1. Show/log die Ausnahme, wie Sie fit
  2. Stellen Sie sicher, Ausfahrt/kill das Bewerbungsverfahren
  3. sehen

Wenn Sie denken, Element zwei ist seltsam, denken Sie daran, dass wir nur die Mühe machen, dies in erster Linie für wirklich außergewöhnliche Situationen zu tun. Diese Dinge sind wahrscheinlich Fehler, bei denen Änderungen an Ihrer Anwendung genau behandelt werden müssen. Jede andere Ausnahmebehandlung - die funktionale Art - sollte tiefer in Ihrem eigentlichen Programmcode liegen, bestimmte Arten von Ausnahmen fangen, wo dies sinnvoll ist, und sie dort in der Weise behandeln, wie es sinnvoll ist. Alles andere sollte Blase bis zu Ihrem FatalExceptionHandler an sich bekannt zu machen und die möglicherweise verkrüppelte Programm stoppen aus beschädigten Zustand arbeiten

Tote Programme erzählen keine Lügen ... ;-)

+0

+1 für Dead-Programme erzählen keine Lügen ... ;-) –

+1

Wie Sie hier sehen können [Warum ist UnhandledExceptionEventArgs.ExceptionObject ein Objekt und keine Ausnahme?] (Http://stackoverflow.com/questions/913472/why-is-unhandledexceptioneventargs-exceptionobject-an-object-and-not- Eine Ausnahme: post, es * kann * unklug sein, 'e.ExceptionObject' in' Exception' zu transformieren, ohne vorher zu checken, da es nicht immer vom Typ 'Exception' ist ... Sie könnten am Ende ein neues '' erstellen Ausnahme 'hier. – Sheridan

+0

Fragte sich, warum es Objekt war, aber sah nie wirklich in das hinein. Ich habe heute etwas Neues gelernt. Vielen Dank! Wird die Antwort ändern, um dies zu beheben. – peSHIr

2

Vielleicht, was Sie suchen ist Environment.Exit(int errorcode)

1

Dieses Verhalten ist von Entwurf.

Aber dort ist ein Work-Around.

Entweder Sie rufen Process.GetCurrentProcess().Kill(); innerhalb des Handlers, oder lassen Sie einfach nicht den Handler zu beenden.

Schauen Sie sich das Beispiel:

class Program 
{ 
    void Run() 
    { 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 

     Console.WriteLine("Press enter to exit."); 

     do 
     { 
      (new Thread(delegate() 
      { 
       throw new ArgumentException("ha-ha"); 
      })).Start(); 

     } while (Console.ReadLine().Trim().ToLowerInvariant() == "x"); 


     Console.WriteLine("last good-bye"); 
    } 

    int r = 0; 

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Interlocked.Increment(ref r); 
     Console.WriteLine("handled. {0}", r); 
     Console.WriteLine("Terminating " + e.IsTerminating.ToString()); 

     Thread.CurrentThread.IsBackground = true; 
     Thread.CurrentThread.Name = "Dead thread";    

     while (true) 
      Thread.Sleep(TimeSpan.FromHours(1)); 
     //Process.GetCurrentProcess().Kill(); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("..."); 
     (new Program()).Run(); 
    } 
} 

Dies sollte kein Standard-Senke für Ausnahmen, sicher sein.

Aber dies sollte getan werden, um Ausnahmen anmutig zu melden.

Verwandte Themen