Ausgabe von Exceptions

  • C#

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Ausgabe von Exceptions

    Hi Leute,

    ich frage mich schon seit einiger Zeit was Leute dazu bewegt, eine Exception unvollständig auszugeben.
    Was ich damit meine, ist dass ich in letzter Zeit gehäuft gesehen habe, dass von einer Exception nur die .Message Property benutzt wird. Seit ich das das erste mal gesehen habe, frage ich mich, warum man nicht gleich die ganze Exception ausgibt?

    Hier mal ein Beispiel anhand eines kleinen Formulares:

    C#-Quellcode

    1. public partial class Form1 : Form
    2. {
    3. public Form1()
    4. {
    5. InitializeComponent();
    6. }
    7. private void btnMessage_Click(object sender, EventArgs e)
    8. {
    9. try
    10. {
    11. throw new NullReferenceException();
    12. }
    13. catch (Exception ex)
    14. {
    15. MessageBox.Show(ex.Message);
    16. }
    17. }
    18. private void btnException_Click(object sender, EventArgs e)
    19. {
    20. try
    21. {
    22. throw new NullReferenceException();
    23. }
    24. catch (Exception ex)
    25. {
    26. MessageBox.Show(ex.ToString());
    27. }
    28. }
    29. }



    Wenn ich auf den ersten Button Klicke, bekomme ich folgende Meldung:

    Ja super. Es ist eine Exception aufgetreten. Irgendwo in meinem Code der hinter diesem Button liegt, der irgendeine komplexe Funktionalität in Gang setzt, bei der ich nicht nur Dinge von der Platte lese, sondern noch eine Datenbank abfrage, und was an nen WebService Schicke. Na dann mach ich mich mal auf die Suche.

    Beim zweiten Button sieht dass dann so aus:

    Yay, ich sehe nun an welcher Stelle im Code der Fehler aufgetreten ist, und die gesamte Aufrufliste, sodass ich nachvollziehen kann, wie die Anwendung an diesen Punkt gelangt ist. Das macht die Fehlersuche einfacher.

    Aber, das interessanteste passiert dann, wenn man eine Exception überhaupt nicht abfängt:

    Neben dem eigenen Code, sieht man hier nun auch welchen Weg die Anwendung im verwendeten Framework genommen hat. Wenn man also Control-Libraries oder Frameworks wie DevExpress benutzt, kann einem das nicht-fangen von Exceptions sogar dabei behilflich sein Fehler in Code zu finden, den man nicht geschrieben hat. Vorausgesetzt, man hat darauf Zugriff. Andernfalls kann man damit immerhin dem Entwickler bescheid geben. Und als Sahnehäubchen werden die meisten User von diesem Dialog eher abgeschreckt, und beenden das Programm, sodass sie nicht mit einem unbekannten Zustand weiterarbeiten.

    Nicht falsch verstehen. Natürlich geht nichts über richtiges Testen und Debuggen in der IDE. Jeden Fehler, jede Exception die wir hier finden, ist nicht nur am schnellsten behoben, sondern taucht auch nie beim Anwender auf. Doch für den Fall dass man eben doch mal eine Exception übersieht, finde ich, ist es wichtig sich nicht selbst Steine in den Weg zu legen, indem man der Exception die Möglichkeit nimmt wichtige Infos, vielleicht sogar die wichtigsten Infos mitzuteilen.

    Nun also meine Frage, wie kommt es dazu, dass man so oft das absolut nicht hilfreiche ex.Message sieht, anstatt dem wesentlich Hilfreicheren ex.ToString() (Im Falle von Console bzw. Debug.WriteLine() sogar nur ex ?)
    SIMDoku (Simple Dokumentenverwaltung)
    Mein Lernprojekt um die verschiedensten Facetten der .NET Entwicklung zu erkunden.
    GitHub

    VB Paradise Dark Theme
    Inoffizieller VB-Paradise Discord.
    @EaranMaleasi Ich baue da gern etwas größere Konstrukte.
    Im Program.cs sieht das dann etwa so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. #if DEBUG
    2. // Exceptions im Debug an Ort und Stelle knallen lassen!
    3. Application.Run(new AppContext(args));
    4. #else
    5. // Exceptions im Debug an Ort und Stelle knallen lassen!
    6. Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
    7. Application.ThreadException += new ThreadExceptionEventHandler(Program.OnThreadException);
    8. AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(Program.OnUnhandledException);
    9. NativeMethods.EnableStandby(false);
    10. try
    11. {
    12. Application.Run(new AppContext(args));
    13. }
    14. catch (Exception ex)
    15. {
    16. Program.MainExceptionHandler(ex);
    17. Error.Log(ex);
    18. }
    19. #endif
    In den einzelnen Klassen dann so:
    Spoiler anzeigen

    C#-Quellcode

    1. catch (Exception ex)
    2. {
    3. Error.Log(ex);
    4. }
    oder so:

    C#-Quellcode

    1. catch
    2. {
    3. #if DEBUG
    4. if (System.Diagnostics.Debugger.IsAttached)
    5. {
    6. // sofort aufklären
    7. System.Diagnostics.Debugger.Break();
    8. }
    9. #endif
    10. }
    Beim Logging wird dann neben der Meldung noch der StackTrace ausgegeben.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Häufig ist es ja gar nicht nötig, das Programm abzubrechen, sondern einfach dem Benutzer die entsprechenden Meldungen auszugeben.
    Gar nichts abzufangen, gibt zwar alle für den Entwickler notwendigen Informationen her, überfordert aber den Anwender.
    Das ist nur im Debug-Modus sinnvoll.
    Der Ansatz von @RodFromGermany, im Debug-Modus auf Break laufen zu lassen, gefällt mir gut.

    Mein übliches Verfahren im Release-Modus:
    Für die Ausgabe an den User loope ich rekursiv durch die Exception und alle InnerExceptions und gebe jeweils ex.Message aus.
    Ins LogFile schreibe ich ex.ToString.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    petaod schrieb:

    im Debug-Modus auf Break laufen zu lassen
    Früher hatte ich da ein Debug.Assert(false) drinne stehen: Fehler finden und Fehler vermeiden mit Debug.Assert(AUSDRUCK)
    aber die Meldung kommt nur im GUI-Thread, nicht aber in einem anderen Thread.
    Deshalb mache ich jetzt praktisch überall das Debugger.Break() rein, auch wenn ein Sinnigkeitstest false liefert.
    Mit nem richtigen Kommentar ist dann auch in einem halben Jahr noch klar, was da zu tun ist. :thumbsup:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!