Forum: PC-Programmierung c# try - catch - Fehlerbehandlung


von Sven L. (sven_rvbg)


Lesenswert?

Guten Abend an alle Mitforisten,
ich wollte hier mal eine Diskussion zum Thema Fehlerbehandlung in C# 
starten.

Klar ist, das viele Methoden bei Fehlschalg eine Exception "werfen".

Nun ist die Frage wie viel try und catch ist sinnvoll.

Jede Funktion die einen Fehler werfen kann in einen eigenen try-catch 
Block zu stecken ist ja aus meiner Sicht in den wenigsten Fällen 
sinnvoll oder möglich.

Hauptziel sollte meiner Meinung nach sein, das die Anwendung nicht 
abstürzt und weiterläuft.

Mich würde an dieser Stelle interessieren, wie es andere machen. 
Natürlich interessiert mich auch die Frage wie man möglichst frühzeitig 
merkt, das an gewissen Stellen eine Fehlerbehandlung sinnvoll wäre. Klar 
Manual lesen, aber unter umständen übersieht man ja auch mal was.

Nun will man nicht bei jeder Exception den Benutzer verrückt machen, 
aber man will eventuell eine Möglichkeit haben Fehler die üblicherweise 
auf dem Entwicklungsrechner nicht auftreten irgendwie doch 
nachvollziehen zu können.

Logs schreiben und Loglevel wie man es aus dem Linuxumfeld kennt wären 
eine Idee. Hat jemand noch weitere?

Ich freue mich auf einen Erfahrungsaustausch und eine Diskussion zum 
Thema und wünsche an der Stelle schonmal ein schönes Wochenende!

von guest (Gast)


Lesenswert?

Sven L. schrieb:
> Hauptziel sollte meiner Meinung nach sein, das die Anwendung nicht
> abstürzt und weiterläuft.

Kommt auf den Fehler an. Manchmal ist weiterlaufen sinnlos bis 
unmöglich. Im Extremfall kann die Anwendung nicht mal mehr eine 
Fehlermeldung ausgeben, dann ist es besser gezielt abzustürzen und dem 
OS das rummeckern zu überlassen als die Anwendung ohne jegliche Meldung 
einfach zu beenden.

von dunno.. (Gast)


Lesenswert?

Ich mache das immer so, dass ich exceptions die ich vorahne (tcp ip 
kommunikation schlägt fehl)

Per try catch abfange, den nutzer informiere, und weiterlaufe, wenn 
möglich.

Plan b ist dann der handler für die uncaught exceptions..

von Noch einer (Gast)


Lesenswert?

Habe inzwischen die Meinung - dieses Feature so weit wie möglich 
ignorieren.

Die Fehlerfälle lassen sich ja nicht vollständig testen. In dem alten 
System mussten wir uns von Anfang an Gedanken machen, wie behandeln wir 
Errorcodes/Nullpointer... Bei jeder Funktion mussten wir uns Gedanken um 
die Fehlerfälle machen.

Mit den Exceptions sagen wir einfach - soll sich das GUI-Modul drum 
kümmern. Nur das andere Team weiss gar nicht, dass es sich da um irgend 
welche Low-Level-Fehler kümmern muss.

Das Ergebnis - beim Kunden tritt ein Fehler auf, den wir nicht 
reproduzieren können. Da kommt dann nur eine Dialogbox, mit der keiner 
was anfangen kann. Keiner versteht mehr, wo überhaupt das Problem liegt. 
Und wie der Fehler überhaupt behandelt werden muss.

von Peter II (Gast)


Lesenswert?

Noch einer schrieb:
> Habe inzwischen die Meinung - dieses Feature so weit wie möglich
> ignorieren.

sehr sinnvoll für professionelle Softwareentwicklung

> Das Ergebnis - beim Kunden tritt ein Fehler auf, den wir nicht
> reproduzieren können. Da kommt dann nur eine Dialogbox, mit der keiner
> was anfangen kann. Keiner versteht mehr, wo überhaupt das Problem liegt.
> Und wie der Fehler überhaupt behandelt werden muss.
bei C# ist es doch überhaupt kein Problem in den Details einer 
Fehlermeldung gleich noch den CallStack auszugehen. Damit lassen sich 
Fehler sehr einfach finden.

von Sven L. (sven_rvbg)


Lesenswert?

Peter II schrieb:
> bei C# ist es doch überhaupt kein Problem in den Details einer
> Fehlermeldung gleich noch den CallStack auszugehen. Damit lassen sich
> Fehler sehr einfach finden.

Da hast Du recht, allerdings finde ich immer diese Ausgaben machen einen 
schlechten Eindruck vorm Kunden bzw. sorgen für Unsicherheit bei diesem.

Auch bin ich der Meinung das man bei C# teilweise gar keine ander Chance 
mehr hat wie try - catch, da die Funktionen nicht immer -1 oder sonstwas 
zurückgeben bei einem Fehler.

Die frage ist nur nach wie vor, wieviel try catch ist sinnvoll und wie 
machen andere es?

von Peter II (Gast)


Lesenswert?

Sven L. schrieb:
> Auch bin ich der Meinung das man bei C# teilweise gar keine ander Chance
> mehr hat wie try - catch, da die Funktionen nicht immer -1 oder sonstwas
> zurückgeben bei einem Fehler.

ja, weil das Konzept so ist.

return hat den großen Nachteil das man keine zusätzlichen Infos 
zurückgeben kann. Das das abfragen der Returns auch gerne vergessen 
wird.

> Da hast Du recht, allerdings finde ich immer diese Ausgaben machen einen
> schlechten Eindruck vorm Kunden bzw. sorgen für Unsicherheit bei diesem.
man muss es halt etwas schön machen. z.b. ein Button - "Fehlermeldung an 
Hersteller schicken".

> Die frage ist nur nach wie vor, wieviel try catch ist sinnvoll und wie
> machen andere es?
überall wo ich auf Fehler reagieren muss kommt ein try catch hin.

Aber auf keine Fall wie einige, einfach ein try catch und im catch 
wieder eine Throw machen.

von Noch einer (Gast)


Lesenswert?

> und wie machen andere es?

Theoretisch oder in der Realität?

Das Problem ist ja gerade, dass es in "historisch gewachsener Software" 
keinen konsistenten Ansatz gibt. Dazu kommt dann noch: Das "catch" wird 
solange aufgeschoben, bis keine Zeit mehr ist, es vernünftig zu machen.

von Arc N. (arc)


Lesenswert?

Peter II schrieb:
> Sven L. schrieb:
>> Auch bin ich der Meinung das man bei C# teilweise gar keine ander Chance
>> mehr hat wie try - catch, da die Funktionen nicht immer -1 oder sonstwas
>> zurückgeben bei einem Fehler.
>
> ja, weil das Konzept so ist.
>
> return hat den großen Nachteil das man keine zusätzlichen Infos
> zurückgeben kann. Das das abfragen der Returns auch gerne vergessen
> wird.

Mit C# 7 geht es endlich, da dort Tupel elegant nutzbar sind.
https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/
oder man macht es krude mit Out-Parametern oder Nullable.

Zu Exceptions und C#:
Kurze Übersicht über fatale, boneheaded, ärgerliche und exogene 
Ausnahmen
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/

Tendiere, so es möglich ist, zu Tupeln. Alles wo ein Fehler auftreten 
kann liefert ein Tupel zurück bspw. File-Handle und Fehler. Mittlerweile 
wird es mit Go verknüpft, obwohl das funktionale Sprachen weit vorher 
konnten.
https://blog.golang.org/error-handling-and-go

von Jan H. (j_hansen)


Lesenswert?

Sven L. schrieb:
> Nun ist die Frage wie viel try und catch ist sinnvoll.

Man kann aus allem eine Wissenschaft machen. Aber grundsätzlich ist es 
ganz einfach:
-) Kann eine Funktion einen Fehler nicht selbst behandeln, so wirft sie 
eine Ausnahme.
-) Kann eine Funktion eine geworfene Ausnahme behandeln, so kommt die 
werfende Funktion in einen Try-Catch-Block.

> Jede Funktion die einen Fehler werfen kann in einen eigenen try-catch
> Block zu stecken ist ja aus meiner Sicht in den wenigsten Fällen
> sinnvoll oder möglich.

Das ist sinnlos. Wenn der Fehler hier nicht behandelt werden kann, dann 
braucht man auch kein Try-Catch.

Sven L. schrieb:
> Nun will man nicht bei jeder Exception den Benutzer verrückt machen,
> aber man will eventuell eine Möglichkeit haben Fehler die üblicherweise
> auf dem Entwicklungsrechner nicht auftreten irgendwie doch
> nachvollziehen zu können.

Wenn der Benutzer davon nichts wissen muss, dann loggen. Ansonsten muss 
der Benutzer ja sowieso eine Meldung bekommen, da kann man den 
Stacktrace auch einblendbar machen.

Noch einer schrieb:
> Die Fehlerfälle lassen sich ja nicht vollständig testen. In dem alten
> System mussten wir uns von Anfang an Gedanken machen, wie behandeln wir
> Errorcodes/Nullpointer... Bei jeder Funktion mussten wir uns Gedanken um
> die Fehlerfälle machen.

Naja, wer zu faul ist Exceptions zu behandeln, dem sind Rückgabewerte 
erst recht egal. Die fragt man einfach nicht ab, noch einfacher als bei 
Exceptions.

> Mit den Exceptions sagen wir einfach - soll sich das GUI-Modul drum
> kümmern. Nur das andere Team weiss gar nicht, dass es sich da um irgend
> welche Low-Level-Fehler kümmern muss.

Selbstverständlich kümmert sich die GUI nicht um Low-Level-Fehler. Das 
soll sie gar nicht. Dein "kümmern muss" ist völlig fehl am Platz.

> Das Ergebnis - beim Kunden tritt ein Fehler auf, den wir nicht
> reproduzieren können. Da kommt dann nur eine Dialogbox, mit der keiner
> was anfangen kann. Keiner versteht mehr, wo überhaupt das Problem liegt.
> Und wie der Fehler überhaupt behandelt werden muss.

Eine Exception liefert viele nützliche Informationen. Wenn man die 
wegwirft und nur "Unbekannter Fehler" anzeigt... Ich denke da muss man 
nicht mehr dazu sagen.
Aber wie das mit irgendwelchen Rückgabecodes besser sein soll, musst du 
mir erst erklären.

von Peter II (Gast)


Lesenswert?

Arc N. schrieb:
> Mit C# 7 geht es endlich, da dort Tupel elegant nutzbar sind.
> https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/
> oder man macht es krude mit Out-Parametern oder Nullable.

wenn man das will kann man ja eine struct zurückgeben. Geht also jetzt 
schon.

Ich finde es viel zu umständlich, ich habe ausrechend C-Code gesehen wo 
vergessen wurde Fehler auszuwerten oder der code zu 90% aus 
Fehlerbehandlung besteht - was mit exception viel übersichtlicher 
geworden ist.

>
> Zu Exceptions und C#:
> Kurze Übersicht über fatale, boneheaded, ärgerliche und exogene
> Ausnahmen
> https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/

man findet zu jedem Konzept Leute die etwas daran auszusetzen haben.

> Tendiere, so es möglich ist, zu Tupeln. Alles wo ein Fehler auftreten
> kann liefert ein Tupel zurück bspw. File-Handle und Fehler. Mittlerweile
> wird es mit Go verknüpft, obwohl das funktionale Sprachen weit vorher
> konnten.
> https://blog.golang.org/error-handling-and-go

Da das Framework mit Exceptions arbeitet, mach es für mich keine sinnen 
oben drauf eine andere Fehlerbehandlung einzusetzen.
Dann muss man halt eine andere Sprache einsetzen.

von Sven L. (sven_rvbg)


Lesenswert?

An der Stelle schon mal danke für die Antworten.


Ich glaube ich werde ein Log schreiben und in der App.Config 
verschiedene Loglevel einstellbar machen.

bzw. kann man hat man ja auch noch die Möglichkeit mit einem 
Komandozeilenargument seine Anwendung gesprächiger zu machen.

Meine Überlegungen rühren daher, sich einmal möglichst viele Gedanken zu 
machen und die Lösung am Ende wieder verwendeen zu können...

von Slippin J. (gustavo_f)


Lesenswert?

Jan Hansen hat richtig beschrieben wie man Exceptions behandelt. In C++ 
mache ich das genau so (leider kann man da keinen Stack trace 
dranhängen).

Nur weil eine Funktion eine Exception wirft, muss diese Funktion nicht 
direkt in einen try-catch-Block eingebettet sein. Man reicht die 
Exception so weit nach oben, bis sie sinnvoll verarbeitet werden kann.

: Bearbeitet durch User
von Sven L. (sven_rvbg)


Lesenswert?

Peter II schrieb:
>> Die frage ist nur nach wie vor, wieviel try catch ist sinnvoll und wie
>> machen andere es?
> überall wo ich auf Fehler reagieren muss kommt ein try catch hin.
>
> Aber auf keine Fall wie einige, einfach ein try catch und im catch
> wieder eine Throw machen.

Ja aber wenn ich nun eine Eigene Klasse schreibe, meinetwegen einen 
Mailer und in dieser Klasse verschiedene Exceptions behandeln will wie 
meinetewegen Authentifizierungsfehler und so weiter... Dann wäre es doch 
nur richtig, wenn ich im catch-Block wieder eine Exception werfe, da ich 
meine klasse ja an verschiedenen Stellen einsetze und meinetewegen 
diesen Fehler nur anzeigen lassen will, wenn ich in der GUI auf Testmail 
senden drücke und im restlichen Programm soll der Fehler ins log 
wandern.

von Peter II (Gast)


Lesenswert?

Sven L. schrieb:
> ... Dann wäre es doch
> nur richtig, wenn ich im catch-Block wieder eine Exception werfe

nein, warum sollte das richtig sein? Damit verhinderst du nur eine 
sinnvoll Fehler suche, weil du die echte Exception nicht mehr hast.

Es spielt doch überhaupt keine Rolle, ob es ein Test ist oder nicht. Der 
Aufrufer muss die Exception abfangen, wenn es eine Test-Button ist, dann 
zeigt er die Fehlermeldung an, wenn es ein Hintergrundprozess ist, dann 
scheibt er es ins log.

von Sven L. (sven_rvbg)


Lesenswert?

Jo und wie mache ich das, wenn ich eine Klasse "Mailer" habe, in der 
irgendwas vom .NetFramework die Exception wirft, dann muss ich diese ja 
in meiner Klasse "Mailer" behandeln.

Da ich die Klasse nun an verschiedenen Stellen im Programm 
unterschiedlich verwende, muss meine Klasse ja den Fehler weiterreichen, 
da die Klasse selbst keine GUI-Elemente beinhaltet.

Ich kann doch die orginale Exception weiter geben vermute ich.

Der oben genannte Test-Button wird zum Beispiel nicht von der 
Mailerklasse bereitshetllt sondern ist Teil einer GUI, die auf die 
Klasse zugreift.

von Sheeva P. (sheevaplug)


Lesenswert?

Sven L. schrieb:
> Klar ist, das viele Methoden bei Fehlschalg eine Exception "werfen".
>
> Nun ist die Frage wie viel try und catch ist sinnvoll.

Das kommt darauf an -- aber im Grunde gilt: je mehr, desto besser.

> Jede Funktion die einen Fehler werfen kann in einen eigenen try-catch
> Block zu stecken ist ja aus meiner Sicht in den wenigsten Fällen
> sinnvoll oder möglich.

Das ist auch nicht die Idee von Exceptions -- im Gegenteil. Die Idee von 
Exceptions ist, daß man eben nicht jeden einzelnen Funktionsaufruf 
prüfen muß, sondern den ganzen kritischen Codeblock in einen try{}-Block 
packen kann und im Fehlerfalle trotzdem sinnvolle Informationen darüber 
bekommt, in welcher Funktion genau welcher Fehler aufgetreten ist -- und 
im besten Fall sogar, wie sie aufgerufen worden ist.

> Hauptziel sollte meiner Meinung nach sein, das die Anwendung nicht
> abstürzt und weiterläuft.

Wie auf einen Fehler reagiert werden muß, hängt von dem Fehler ab! Ein 
Programm, das genau eine einzige Datei lesen muß und diese nicht findet, 
sollte mit einer passenden, vor allem einer möglichst aussagekräftigen 
Fehlermeldung und entsprechendem Rückgabewert beendet werden.

Aber wenn ein Programm mehrere Dateien lesen soll und eine davon nicht 
findet: dafür gibt es kein allgemeines Rezept. War die nicht gefundene 
Datei für die Funktion des Programms unerläßlich: wie vor, Programm mit 
entsprechender Fehlermeldung sterben lassen. War das nur eine Datei, die 
für die Gesamtfunktion des Programms nicht zwingend notwendig ist: 
sollte das Programm eine entsprechende Fehlermeldung ausgeben, aber 
weiterlaufen und die gefundenen Dateien verarbeiten.

> Mich würde an dieser Stelle interessieren, wie es andere machen.

Es gibt kein "Standardkonzept". Es mag sich blöd anhören, aber ich mache 
das, was ein Entwickler tut: ich benutze mein Gehirn. Bei jeder Nutzung 
externer Ressourcen (Dateien, Netzwerkverbindungen, RAM Allocation etc.) 
denke ich darüber nach, wie wichtig die Ressource für den korrekten 
Ablauf des Programms ist.

Beispiel 1: ich habe ein Programm, das eine Datenbank bearbeiten soll, 
und die Verbindungsparameter zur Datenbank stehen in einer 
Konfigurationsdatei.  Wenn ich in diesem Fall die Konfigurationsdatei 
nicht öffnen kann, würde mein Programm eine Fehlermeldung ausgeben und 
sich sauber beenden.

Beispiel 2: ich habe ein Programm, das einige tausend CSV-Dateien in 
einem Verzeichnis statistisch auswerten soll. Gleichzeitig verarbeiten 
andere Programme die CSV-Dateien in dem Verzeichnis, und schieben 
Dateien hinein oder löschen welche. Wenn ich in diesem Fall eine Datei 
mal nicht öffnen könnte, würde ich eine Fehlermeldung ausgeben und mit 
der nächsten Datei weitermachen.

Der Fehler ist in beiden Fällen derselbe: ich konnte eine Datei nicht 
öffnen. Aber die Reaktionen darauf sind völlig verschieden.

> Natürlich interessiert mich auch die Frage wie man möglichst frühzeitig
> merkt, das an gewissen Stellen eine Fehlerbehandlung sinnvoll wäre. Klar
> Manual lesen, aber unter umständen übersieht man ja auch mal was.
>
> Nun will man nicht bei jeder Exception den Benutzer verrückt machen,
> aber man will eventuell eine Möglichkeit haben Fehler die üblicherweise
> auf dem Entwicklungsrechner nicht auftreten irgendwie doch
> nachvollziehen zu können.

Das ist eine Erfahrungssache, für die es keine Standardrezepte gibt und 
auch keine geben kann. Die Frage, die Du Dir stellen mußt, ist immer: 
welche Fehler können auftreten, und welchen Einfluß haben sie auf den 
weiteren Ablauf meines Programms -- und auf das Ergebnis, das der User 
Deines Programms von demselben erwartet.

> Logs schreiben und Loglevel wie man es aus dem Linuxumfeld kennt wären
> eine Idee. Hat jemand noch weitere?

Nein, aber da ich nur unter und weitestgehend für Linux entwickle, habe 
ich die entsprechenden Features natürlich. Es würde mich aber sehr 
verwundern, wenn Windows' Eventlogs keine ähnlichen Möglichkeiten 
hätten. Ansonsten ist es unter Linux eine probate Methode, eigene 
Logdateien zu schreiben -- das geht sicher auch unter Windows.

von Sheeva P. (sheevaplug)


Lesenswert?

Sven L. schrieb:
> Ja aber wenn ich nun eine Eigene Klasse schreibe, meinetwegen einen
> Mailer und in dieser Klasse verschiedene Exceptions behandeln will wie
> meinetewegen Authentifizierungsfehler und so weiter...

Solche Fehler darf eine Mailer-Klasse nicht selbst behandeln (außer, um 
sie zu loggen). Nur die nächsthöhere Schicht -- der "Nutzer" der Klasse 
-- kann wissen, wie ein solcher Fehler zu behandeln ist.

> Dann wäre es doch nur richtig, wenn ich im catch-Block wieder eine
> Exception werfe,

Es wäre sogar richtig, wenn Du im catch{}-Block wieder genau dieselbe 
Exception werfen würdest. Die meisten Programmiersprachen, die 
Exceptions unterstützen, machen das mit einem einfachen "throw" oder 
"raise" ohne Parameter. Soweit ich weiß, kann das auch C#.

> da ich
> meine klasse ja an verschiedenen Stellen einsetze und meinetewegen
> diesen Fehler nur anzeigen lassen will, wenn ich in der GUI auf Testmail
> senden drücke und im restlichen Programm soll der Fehler ins log
> wandern.

Dann mußt Du den Fehler an den verschiedenen Stellen Deines Programms 
abfangen und unterschiedlich behandeln -- dazu sind Exceptions da: sie 
enthalten sehr detaillierte Informationen über die Art des aufgetretenen 
Fehlers, und anhand dieser Informationen kannst Du an jeder Stelle des 
Programms fein granuliert entscheiden, wie es darauf reagieren soll.

Und ja, in bestimmten Fehlersituationen ist ein Abbruch des Programms 
einfach nichts anderes als sinnvoll -- und in anderen eben nicht. Es ist 
Deine Aufgabe, das zu unterscheiden und angemessen darauf zu reagieren.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.