Forum: PC-Programmierung C# Ausnahmebehandlung


von H. C. (sunshine)


Lesenswert?

Hi,
was ist eigentlich besser an "try - catch", bei Prüfung von 
Ausnahmebehandlungen bei User-Eingaben, als an einem "if - else"?

von Arne Maximilian R. (arnemaximilian_r)


Lesenswert?

try-catch kann ohne Probleme auf hoehere Codeebenen weiter geleitet 
werden. Du musst dafuer nicht in jeder aufrufenden Funktion eine 
Behandlung des Problems einbauen, sondern kannst es direkt auf der 
obersten Aufrufebene behandeln. if-else erwartet dagegen mehr 
Schreibarbeit und Verwaltung beim Aufruf.

von setjmp (Gast)


Lesenswert?

Der Lesbarkeit des Codes zuliebe sollten Exceptions m.M.n. hauptsächlich 
zur Behandlung von Ausnahmesituationen eingesetzt werden, nicht aber zur 
Steuerung des allgemeinen Kontrollflusses. Ein User, der Unfug eingibt, 
ist keine Ausnahmesituation, sondern zu erwarten. Behandeln 
Programmierer derartige Situationen (wie auch das Ausfallen des 
Netzwerks o.ä.) wie einen Ausnahmezustand, merkt man das dem 
resultierenden Programm oft an seiner mangelnden Robustheit an. ;-)

von Tobias K. (t_k)


Lesenswert?

Stimme setjmp voll zu:
Ausnahme <-> erwartetes Verhalten.

Aber Deine Frage müsste eigentlich "Throw oder if-then-else" lauten.
Das try-catch findet ja eine Ebene weiter 'oben' statt.

Ausnahmebehandlungen sind teuer, deshalb sollten sie nicht für alles 
eingesetzt werden, nur für "alles, was das Programm an der Stelle nicht 
lösen kann".

Beispiel: Dein Parser, der einen Dateiinhalt verarbeitet (Stream) 
bekommt eine I/O Exception. Die wird er wohl weiterwerfen, da er nix mit 
Dateifehlerhandling zu tun hat und auch nichts Sinnvolles tun kann. 
(Okok, den Parser komplett von IO/Streams zu befreien wäre noch 
sauberer).

Manch einer fängt auch gern mal alle Exception und schreibt dann im 
besten Fall noch einen Fehler ins Log, das ist aber nicht Sinn von 
Exceptions...

von Markus V. (valvestino)


Lesenswert?

Tobias K. schrieb:
> Ausnahmebehandlungen sind teuer, deshalb sollten sie nicht für alles
> eingesetzt werden, nur für "alles, was das Programm an der Stelle nicht
> lösen kann".

Da unterliegst Du einem allgemeinen Irrtum. Nicht die Behandlung von 
Ausnahmen ist per se teuer, sondern das Erzeugen der Exception-Objekte 
kostet richtig viel Zeit.

Gruß
Markus

von Udo S. (urschmitt)


Lesenswert?

Markus Volz schrieb:
> Tobias K. schrieb:
>> Ausnahmebehandlungen sind teuer, deshalb sollten sie nicht für alles
>> eingesetzt werden, nur für "alles, was das Programm an der Stelle nicht
>> lösen kann".
>
> Da unterliegst Du einem allgemeinen Irrtum. Nicht die Behandlung von
> Ausnahmen ist per se teuer, sondern das Erzeugen der Exception-Objekte
> kostet richtig viel Zeit.

Habt ihr da mal Zahlen, was ist denn "richtig teuer" und "kostet richtig 
viel Zeit"?
Eine Exception ist genau das was das Wort sagt. Eine nicht normale 
Bedingung, die eben auch nicht normal verarbeitet werden kann. In den 
meisten Fällen führt so eine Bedingung zum Abbruch dessen was das 
Programm gerade tut, oder es ist sogar ein fataler Programmierfehler, 
und genau so sollten Exceptions benutzt werden.
Beispiele I/O Error, DB Error, Division durch Zero, Null Pointer 
Exception, Cast Exception, Konvertierfehler (String in Zahl), ...
Und in den Fällen ist die Performance genau wie bei benutzereingaben das 
allerletzte was wichtig ist.

Tobias K. schrieb:
> Manch einer fängt auch gern mal alle Exception und schreibt dann im
> besten Fall noch einen Fehler ins Log, das ist aber nicht Sinn von
> Exceptions...

Was willst du sonst tun, wenn die Datei nicht da ist, die Datenbank 
einen Fehler wirft, der Parser sagt das XML ist fehlerhaft?
Ein Back office Programm oder ein Daemon kann schlecht den User fragen.

: Bearbeitet durch User
von Arne Maximilian R. (arnemaximilian_r)


Lesenswert?

Udo Schmitt schrieb:
> Eine Exception ist genau das was das Wort sagt. Eine nicht normale
> Bedingung, die eben auch nicht normal verarbeitet werden kann. In den
> meisten Fällen führt so eine Bedingung zum Abbruch dessen was das
> Programm gerade tut, oder es ist sogar ein fataler Programmierfehler,
> und genau so sollten Exceptions benutzt werden.

Wuerde ich auch so sagen. Steht im Flussdiagramm nicht, dass der 
Benutzer mehrfach abgefragt werden soll (bis es ein richtiges Ergebnis 
gibt), dann ist es eine Ausnahme im Ablauf, die entsprechend behandelt 
werden sollte.

von Markus V. (valvestino)


Lesenswert?

Udo Schmitt schrieb:
> Habt ihr da mal Zahlen, was ist denn "richtig teuer" und "kostet richtig
> viel Zeit"?

Ich habe das unter C# mal mit einem Profiler angeschaut und 
festgestellt, dass das erstmalige Erzeugen einer Exception tatsächlich 
im Bereich einiger hundert Millisekunden gedauert hat. Die betreffende 
Assembly war zu diesem Zeitpunkt bereits geladen. Wenn man sich vor 
Augen hält, was eine aktuelle CPU im 500 ms so alles erledigen kann, 
auch unter .NET, wird einem die Tragweite von 100 ms für das Erzeugen 
einer Exception erst richtig klar.

So ein Test hängt natürlich stark von den Begleitumständen ab, zeigt 
aber, dass es ratsam ist, das Erzeugen von Exceptions im normalen 
Programmfluss zu vermeiden und möglichst viele Fälle durch die 
Programmlogik zu erledigen.

Grüße
Markus

von Udo S. (urschmitt)


Lesenswert?

Markus Volz schrieb:
> Ich habe das unter C# mal mit einem Profiler angeschaut und
> festgestellt, dass das erstmalige Erzeugen einer Exception tatsächlich
> im Bereich einiger hundert Millisekunden gedauert hat.

Sorry aber das glaube ich nicht. Ich glaube dir gerne daß der Profiler 
mehrere 100ms angezeigt hat, aber das ist definitiv nicht das Erzeugen 
der Exception. Das war eher der Versuch der API Funktion oder was auch 
immer ein Problem noch zu lösen bevor eine Exception erzeugt wird, z.B. 
durch warten und wiederholen.
Was war das für eine Excetion? File IO oder TCP/IP oder Datenbank würde 
passen, einfach weil da auf externe Peripherie gewartet wird bis zu 
einem Timeoput.
Versuch mal eine Konvertierexception (z.B. nichtnumerischer String in 
Integer konvertieren) in einer Schleife zu programmieren, da wirst du 
sehen, daß du zumindest 100000 oder gar Millionen von Exceptions pro 
Sekunde erzeugen und wieder fangen kannst.

von jibi (Gast)


Lesenswert?

>Versuch mal eine Konvertierexception (z.B. nichtnumerischer String in
>Integer konvertieren) in einer Schleife zu programmieren, da wirst du
>sehen, daß du zumindest 100000 oder gar Millionen von Exceptions pro
>Sekunde erzeugen und wieder fangen kannst.

Weil die "branch predection" anspringt...

Gruß Jonas

von Prog R. (daniel_v)


Lesenswert?

Udo Schmitt schrieb:

> Habt ihr da mal Zahlen, was ist denn "richtig teuer" und "kostet richtig
> viel Zeit"?

Ich habe mal unter C# schön gesehen, was Try/Catch verursacht. (bei 
falscher Verwendung)
Leider gelang mir eine Abfrage auf eine Datenbank nicht so, wie ich es 
wollte  - ich brauchte aber schnell eine Lösung, die funktioniert.

Also habe ich einfach iterativ auf die Datenbank zugegriffen und 
jedesmal, wenn die Abfrage (wurde dynamisch als string erzeugt) schief 
ging, hab ich das mit dem catch gefangen und nichts getan.
Das hat zumindest mal funktionell das gewünschte Ergebnis gebracht.

Also ca:
1
for(int i = 0; i < nCount; i++)
2
{
3
try
4
{
5
 // Datenbankabfrage ausführen
6
}
7
catch
8
{
9
 // nichts tun und weiter in for - Schleife
10
}
11
}
Diese Schleife wurde 50 mal durchlaufen und davon bin ich ca 45 mal im 
Catch gelandet.
Das ganze hat 3-5 Sekunden gedauert - trotz dass die DB (Access) lokal 
am Rechner lief.

Dieselbe Abfrage hat dann in den nächsten Tage, als ich eine saubere 
Lösung fand, naja - praktisch nichts mehr gedauert :)

von Tobias K. (t_k)


Lesenswert?

wie sah denn die saubere Lösung aus?

Grüße,tk

von Prog R. (daniel_v)


Lesenswert?

Tobias K. schrieb:
> wie sah denn die saubere Lösung aus?
>
> Grüße,tk



Prinzipiell geht es darum, dass eine Tabelle wie eine Matrix betrachtet 
wird. Die Spalten stellen Werte dar, zu denen Zeilenwerte aus Spalte 1 
gehören.
Also eine Zuordnungsmatrix. (steht im Feld ein "x", ist die Zuordnung 
gültig)

Werte  A    B     C     D    .   .    .
Wert1  x    x
Wert2  x          x     x
Wert3
.
.
.

Ich hole mir dann die entsprechende Zeile, indem ich die erste Spalte 
dort selektiere, wo der Wert dem Suchwert entspricht. (z.B. Wert2)
Dann suche ich iterativ alle Spalten durch, ob am entsprechenden Index 
ein "x" steht - dies sind dann die in dem Fall gültigen Einträge.

Zuerst hatte ich die Werte A,B,.. als Spaltennamen (Liste war aus 
MSExcel importiert) und führte iterativ über alle Spaltennamen einen 
SELECT aus, der halt, da immer nur eine Spalte gesucht war, zu 95% ins 
catch krachte.

Ich hoffe, das ist so halbwegs verständlich. :)

: Bearbeitet durch User
von bluppdidupp (Gast)


Lesenswert?

Daniel V. schrieb:
> Ich hoffe, das ist so halbwegs verständlich. :)

Ein wenig unklar ist, warum du in SQL-Exceptions läufst, statt nur ein 
leeres Ergebnis zurückzubekommen. Das hört sich irgendwie nach 
ungünstigem DB-Aufbau an.

von Prog R. (daniel_v)


Lesenswert?

bluppdidupp schrieb:
> Daniel V. schrieb:
>> Ich hoffe, das ist so halbwegs verständlich. :)
>
> Ein wenig unklar ist, warum du in SQL-Exceptions läufst, statt nur ein
> leeres Ergebnis zurückzubekommen. Das hört sich irgendwie nach
> ungünstigem DB-Aufbau an.

genau das war der Fall ( siehe letzte Zeile aus meinem letzten Post:
Zuerst hatte ich die Werte A,B,.. als Spaltennamen (Liste war aus
MSExcel importiert) und führte iterativ über alle Spaltennamen einen
SELECT aus, der halt, da immer nur eine Spalte gesucht war, zu 95% ins
catch krachte.)

Ich habe dann die Spaltennamen wieder, wie es Access default mäßig 
macht, mit Laufzähler erhöht (Field1....Fieldn) und die Namen, die ich 
zuerst hatte, in die erste Zeile geschoben. Dann hat's hingehauen.

Es sollte auch angemerkt werden, dass das mein erstes Porjekt war, bei 
dem ich eine Datenbank verwendet habe.
Würde ich jetzt nochmal beginnen, wäre da einiges anders :)

von Alexander B. (leuchte)


Lesenswert?

Udo Schmitt schrieb:
> Habt ihr da mal Zahlen, was ist denn "richtig teuer" und "kostet richtig
> viel Zeit"?

Hier ist ein Artikel von jemand der entsprechende Messungen gemacht hat, 
allerdings für C++ und in Bezug auf Game Engines.

http://www.gamearchitect.net/Articles/ExceptionsAndErrorCodes.html

Die Quintessenz: Ja, Exceptions sind "teurer" als eine 
if-else-Fehlerbehandlung, aber das fällt wirklich nur bei 
High-Performance-Anwendungen ins Gewicht und nicht bei alltäglichen 
Programmieraufgaben.

von Tobias K. (t_k)


Lesenswert?

...bleiben aber trotzdem "Ausnahmen".
Wenn ich was mit "if" prüfen kann, dann erwarte ich das ja schon als 
Möglichkeit.
Was hier im Thread ein wenig in den Hintergrund gerückt ist: Exceptions 
beinhalten eine genaue Fehlerbeschreibung, den Stacktrace und ich kann 
sie weiterwerfen oder neu verpacken, je nach dem, was ich an der Stelle 
machen kann.
Wie oft hab ich schon Frickel-Magic-Numbers als returnvalues gesehen 
:rolleyes:

Trotzdem ersetzen Exceptions keine Fehlerantizipation ( z.B. mit if), 
sind also eigentlich nicht vergleichbar (oder gar "besser"), um mal auf 
den TE einzugehen, sondern halt für einen anderen Zweck gedacht.

Ganz banal: if und try ergänzen sich.

tk

von Tobias K. (t_k)


Lesenswert?

@Daniel es ist noch kein Meister vom Himmel gefallen ;)
Tipp: lass die Spalten auf jeden Fall stabil und Speicher alles in die 
gleiche Tabelle. Das gefällt einem richtigen DBMS (nicht Access) besser 
und ist dann auch mindestens so performant und genauso flexibel.
Konkret: zwei Spalten für die "Koordinate", dritte für den Wert. Je nach 
DBMS kannst Du auf sowas direkt so arbeiten, wie mit der von Dir 
genannten.

tk

von Prog R. (daniel_v)


Lesenswert?

Tobias K. schrieb:

> Konkret: zwei Spalten für die "Koordinate", dritte für den Wert. Je nach
> DBMS kannst Du auf sowas direkt so arbeiten, wie mit der von Dir
> genannten.
Danke für den Tipp.

Die Anforderung ergab sich, hätte ich ja gleich detaillierter 
beschreiben können, daraus, dass ich Ersatzteile Maschinen zuordne.
Natürlich können verschiedene Ersatzteile verschiedenen Maschinen 
zugeordnet werden - aber eben nur einigen von vielen.
Eine Tabelle, die hunderte Ersatzteile ca 50 Maschinen zuordnet, wäre 
ein immenser Einpflegungsaufwand mit zwei "Koordinatenspalten" (wenn ich 
dich richtig verstehe) gewesen und dem wollte ich entfliehen, da es die 
eine Matrix in Excel schon gab.....

von Tobias K. (Gast)


Lesenswert?

Ah. verstehe - diese Anforderungen aus der Officewelt kenne ich nur zu 
gut.
OT: Hier wäre mein Ansatz ein Excel-Makro, das die Koordinaten ermittelt 
und den Wert dazu. Damit trennst du dann Repräsentation/Eingabe und 
Speicherung.

Grüsse, tk

von Dr. Sommer (Gast)


Lesenswert?

Tobias K. schrieb:
> Trotzdem ersetzen Exceptions keine Fehlerantizipation ( z.B. mit if),
> sind also eigentlich nicht vergleichbar (oder gar "besser"), um mal auf
> den TE einzugehen, sondern halt für einen anderen Zweck gedacht.
Naja. Zumindest in C++ kann man dank RAII so programmieren, dass 
Funktionen Exception-sicher (d.h. Exceptions verursachen keinen 
ungültigen Zustand) sind, ohne eine Unmenge try-catch oder if-else 
einzubauen, sondern oft lediglich durch "richtige" Anordnung der 
Anweisungen und ein paar temporäre Variablen mehr. Wird zB bei den 
Containern der stdlib so gemacht; wenn die eine Funktion (zB 
Copy-Constructor) eines enthaltenen Elements aufrufen und die eine 
Exception wirft, ist der Container danach immer noch in einem 
konsistenten Zustand und kann "sauber" zerstört werden.
Typischerweise hat man nur sehr wenige try-catch-Blöcke, die sich dann 
hauptsächlich auf der höchsten Ebene - dort wo man den Benutzer 
benachrichtigen kann - befinden.
Das erlaubt einen übersichtlichen Code der nicht völlig in der 
Fehlerbehandlung versinkt wie das bei exceptionlosem C-Code gerne mal 
ist.

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.