![]() |
Falsche Verwendung von try...except...end
Viele Programmierer verwenden try...except...end auf eine falsche Weise.
Es gibt mindestens 5 "Sünden", die man begehen kann:
Delphi-Quellcode:
Wenn man obige Sünden nicht begeht, wird man belohnt:
// 1. Sünde
// jede Exception wird komplett verschluckt // Niemand wird je erfahren, warum das Programm nicht funktioniert !!! // dass die Exception.Message in der Delphi IDE angezeigt wird zählt nicht, // denn nach Murphy treten Fehler grundsätzlich beim Endbenutzer auf try MachWas; except end; // 2. Sünde // Exceptions werden abgefangen und als Returncode umgesetzt // niemand wird je erfahren, warum eine Funktion einen Fehlercode liefert try MachWas; except Result := 1; // oder auch Result := False; end; // 3. Sünde // Exception wird abgefangen und mit ShowMessage eine Meldung präsentiert // niemand wird je die wahre Ursache erfahren // in einer Schleife können tausende Meldungen produziert werden try MachWas; except ShowMessage('es ist Fehler in MachWas aufgetreten'); // ShowMessage('Es ist ein Fehler aufgetreten !'; // geht's noch genauer ?? Exit; end; // 3. Sünde B // Manchmal führt die Meldung des Programmierers total in die falsche Richtung try liste.LoadFromFile('C:\autoexec.bat'); liste.Add(...) .... liste.SaveToFile('C:\autoexec.bat'); except // die Meldung kann völlig falsch sein. // eine Exception an dieser Stelle bedeutet nicht, dass die AUTOEXEC.BAT nicht vorhanden ist // dann lieber eine nichtssagende Fehlermeldung, als eine Falsche ShowMessage('C:\AUTOEXEC.BAT nicht gefunden !'); Exit; end; // 4. Sünde // Exception wird abgefangen und die Meldung mit ShowMessage präsentiert // die orginale Exception-Class geht verloren (ein Exception-Objekt kann auch mehr Informationen // tragen als nur eine Message (siehe EOleException); die Infos sind verloren) // in einer Schleife können tausende Meldungen produziert werden // es wird zwar jetzt die richtige Meldung angezeigt, aber wenn man mit Exit zurückkehrt // hätte man das try...except gleich weglassen können try MachWas; except on E:Exception do begin ShowMessage(E.Message); Exit; end; end; // 5. Sünde // try...except wird verwendet, um eine Resource (Speicher, Handles,...) zu schützen // Resourcen werden mit einem Resourceschlutzblock (try...finally) geschützt und nicht // mit einem falsch verstandenem try...except // in folgendem Beispiel wird try..except falsch verwendet sl:=TStringList.create; sl.add('[autorun]'); sl.add('OPEN='+app); sl.add('ICON='+icon); if copy(destfile, length(destfile)-4, 4)<>'.inf' then destfile:=destfile+'.inf'; try sl.SaveToFile(destfile); except result:=false; end; sl.free; // Richtig wäre sl:=TStringList.create; // Resource belegen try // direkt danach folgt das try sl.add('[autorun]'); sl.add('OPEN='+app); sl.add('ICON='+icon); if copy(destfile, length(destfile)-4, 4)<>'.inf' then destfile:=destfile+'.inf'; sl.SaveToFile(destfile); finally sl.Free; // die Resource wird immer freigegeben, egal was passiert end; man kann z.B. Exceptions, die bis an die Oberfläche kommen automatisch in einer Log-Datei speichern oder man kann dem Benutzer zusätzlich einen Hilfe-Button (natürlich kontextsensitiv) anbieten. ![]() Man könnte die Exception-Infos auch per Email zum Programmierer schicken lassen. ("Bug-Report" per EMail) Richtige Verwendung von try...except...end
Delphi-Quellcode:
// in folgendem Beispiel werden Daten aus einer Query gelesen
// Fehler werdem in einem Memo protokolliert und der Lesevorgang geht weiter // es werden keine Informationen unterdrückt, sondern die Fehlermeldungen werden protokolliert while not Query1.Eof do begin try MachWas(Query1); except on E:Exception do begin MemoLog.Lines.Add('Fehler in MachWas'); MemoLog.Lines.Add(E.ClassName+':'+E.Message); MemoLog.Lines.Add('Record: ' +IntToStr(Query1.RecNo); end; Query1.Next; // nächster Datensatz end; end; // in folgendem Beispiel wird eine Exception abgefangen mit Informationen angereichert // und erneut ausgelöst try MachWas(x, y, color); except on E:Exception do // Eception abfangen begin // mit *nützlichen Informationen* anreichern // die Meldung wird mehrzeilig durch #13#10 E.Message := Format('Fehler in MachWas(%d, %d, %d)'#13#10, [x, y, color]) + E.Message; Raise; // Erneut auslösen ! end; end; // Manchmal möchte man wirklich jede Exception unterdrücken try anzahl := StrToInt(EditAnzahl.Text); except anzahl := 1; end; // hier empfiehlt es sich die Exception zu vermeiden if EditAnzahl.Text = '' then anzahl := 1 else begin anzahl := StrToInt(EditAnzahl.Text); end; // Es gibt natürlich noch elegantere Lösungen (StrToIntDefault kann sich jeder selber bauen) anzahl := StrToIntDefault(EditAnzahl.Text, 1); |
Re: Falsche Verwendung von try...except...end
2. ist nicht per se eine Suende.
Besonders in DLLs kann es unbedingt notwendig sein Exceptions zu unterdruecken. Das Beispiel schert sich natuerlich nicht um eine genaue Aufschluesselung der Ursache, aber das muss ja nicht immer noetig sein. (immer diese Shreipfeler) |
Re: Falsche Verwendung von try...except...end
Zitat:
Es gibt noch eine weitere Ausnahme: Programmcode, der von Aussen über eine Automatisierungsschnittstelle aufgerufen wird, muss spezielle Vorkehrungen treffen und darf auch ShowMessage zum Anzeigen benutzen, falls der Client die Exception nicht anzeigen kann. |
Re: Falsche Verwendung von try...except...end
Zitat:
Diese Verwendung sollte keinerlei Auswirkungen auf den Schutz haben, sondern vielmehr einen Funktionswert zurückgeben... Wenn du dich schon beschweren willst, dann schreib wenigstens die ganze Funktion auf!
Delphi-Quellcode:
Natürlich hätte man das Ganze durch try...finally schützen können, aber das hielt ich in dem Fall nicht für nötig! Und im Fall einer Wertezuweisung in einer Funktion ist das hier ebenso falsch, weil eine Sicherung NIE GEPLANT war...
function TForm1.CreateAutorunFile(app, icon, destfile: String): boolean;
var sl: TStringList; begin result:=true; //im Grunde erfolgreich sl:=TStringList.create; //TStringlist erstellen sl.add('[autorun]'); //Zeilen schreiben sl.add('OPEN='+app); //-"- sl.add('ICON='+icon); //-"- if copy(destfile, length(destfile)-4, 4)<>'.inf' then destfile:=destfile+'.inf'; //im Zweifelsfall Endung anhängen try sl.SaveToFile(destfile); //Speicherversuch except result:=false; //Gescheitert? Dann false zurückgeben end; sl.free; //Ressource wieder freigeben end;
Delphi-Quellcode:
EDIT: Wir werden uns das mal merken und machen uns dann über dich lustig... Natürlich auch, wenn du mal vollkommen recht haben solltest! Aber diesmal: :kotz: :lol:
sl:=TStringList.create; // Resource belegen
try // direkt danach folgt das try sl.add('[autorun]'); sl.add('OPEN='+app); sl.add('ICON='+icon); if copy(destfile, length(destfile)-4, 4)<>'.inf' then destfile:=destfile+'.inf'; sl.SaveToFile(destfile); finally sl.Free; // die Resource wird immer freigegeben, egal was passiert end; |
Re: Falsche Verwendung von try...except...end
es gibt da noch 'ne Sünde:
Man verwendet die try-except Konstruktion in einer Schleife. Bei einer Schleife, die sehr oft durchlaufen wird, verschlingt das Rechenzeit. |
Re: Falsche Verwendung von try...except...end
Hi all,
bei Delphi is mir mit als erstes aufgefallen, dass man except und finally nicht miteinander verwenden kann. In Java bsw. können folgende Blöcke gebildet werden:
Code:
try
{ ... } except { ... } finally { ... } Da ich auf Exceptions reagieren möchte (log diese in ne Datei), setze ich finally so gut wie gar nicht ein. Jetzt hab ich in dem Beispiel allerdings gelesen, dass mein Ansatz eigentlich falsch ist.
Delphi-Quellcode:
Frag mich nun folgendes:
TRY
... sl:=TStringList.create; // Resource belegen ... EXCEPT on E:Exception do begin Loggen end; END; s1.Free 1. In obigen Beispiel wird doch s1 auch IMMER freigegeben oder hab ich da nen Denkfehler?. 2. Was passiert eigentlich wenn s1 nicht freigegeben wird? Wird nur unnötig Speicher belegt bis das Programm endet? cu Terminator |
Re: Falsche Verwendung von try...except...end
ich finde das erste nicht als Todsünde - Es gibt programme die sind für Leute die 0 Ahnung haben. Wenn diese User bei einem Musikprogramm alle Dateien im Ordner markieren und dem programm hinzufügen wäre es unzumutbar 20 Fehlermeldungen zu bringen weil eventuell Textdateien & Cover mit auf das Programm gedroppt wurden. Oder wenn man beim Start des programmes alle dateien aus einem dump läd und eine wechseldatenträger nicht gefunden wird kann ich nicht bei 20 000 Dateien dem Nutzer jedesmal eine Meldung bringen das die Datei nicht gefunden wurde. Da ist es nutzerfreundlicher wenn die datei einfach nicht geadded wird
|
Re: Falsche Verwendung von try...except...end
Zitat:
Hat der Entwickler 0 Ahnung, muss zwangsläufig der Anwender Ahnung haben. In solchen Fällen versuche ich nicht einfach blind ein .jpg per Mediaplayer abzuspielen, sondern ich (als Entwickler) schaue vorher, was ich denn da für Dateien kriege (Notfalls anhand des Dateinamens). Dann gibt's keine Exceptions und ich kann selber entscheiden ob ich für jede Datei eine Meldung anzeige oder nur für die erste oder überhaupt nicht (letzteres wäre bei sowas wohl das sinnvollste). Zitat:
Die Liste der Sünden gilt für Entwickler mit Grips, für Anfänger sind das garantiert keine Sünden, ganz einfach weil die's nicht besser wissen und nicht die nötige Erfahrung haben. |
Re: Falsche Verwendung von try...except...end
Ich fand des Tut ganz okay :thumb: hat mir das Exceptionhandling etwas näher gebracht :mrgreen: (Exceptions? Brauch ich net :zwinker: )
|
Re: Falsche Verwendung von try...except...end
Ich fand das Tut auch ganz toll, denn ich bin auch so ein Schlumi, der gern mal was in einen solchen Block packt, aber nichts damit anfängt. Ich denke, das ich da demnächst mehr darauf achten werde und das war auch sicher einer der Denkansätze für das Einbringen eines solchen Threads.
|
Re: Falsche Verwendung von try...except...end
Zitat:
2.) Ja. Es wird unnötiger Speicher belegt. Und das u.U. über das Programmende hinaus René |
Re: Falsche Verwendung von try...except...end
Zitat:
nein sl wird nicht freigegeben, weil der Ablauf in den except-Teil springt und anschliessend die procedure verlassen wird. zu 2. du bekommst Speicherlöcher (memory leaks), weil der Speicher belegt bleibt und nicht neu zugewiesen werden kann. Ausserdem kannst Du unerwartete Nebeneffekte bekommen, wenn Du z.B. sl neu erzeugst. Also immer schauen, dass alle mit create angelegte Objekte auch wieder ein free erfahren. |
Re: Falsche Verwendung von try...except...end
:bounce2: Erster !
|
Re: Falsche Verwendung von try...except...end
Zitat:
|
Re: Falsche Verwendung von try...except...end
@Terminator
du kannst try-finally/except auch verschachteln :zwinker: entweder erst die excption behandeln und dann freigeben
Code:
=
try
{ ... } except { ... } finally { ... }
Delphi-Quellcode:
oder erst freigeben und dann die Exception
try
try ... except ... end; finally ... end;
Code:
=
try
{ ... } finally { ... } except { ... }
Delphi-Quellcode:
Aber stimmt schon ... zusammen (als ein Try-Block) hab ich's mir auch schon gewünscht :roll:
try
try ... finally ... end; except ... end; |
Re: Falsche Verwendung von try...except...end
Zitat:
wenn nur noch der Except-Block ausgeführt werden würde, das wäre ja schrecklich. Das ist nicht so! Es kann ja nicht sein, dass man bei ner Exception keine Möglichkeit mehr hat, hinter dem Teil mit der Exception weiterzumachen. Gruß Michael |
Re: Falsche Verwendung von try...except...end
Dass das noch niemandem aufgefallen ist:
Zitat:
Delphi-Quellcode:
// in folgendem Beispiel werden Daten aus einer Query gelesen
// Fehler werdem in einem Memo protokolliert und der Lesevorgang geht weiter // es werden keine Informationen unterdrückt, sondern die Fehlermeldungen werden protokolliert while not Query1.Eof do begin try try MachWas(Query1); except on E:Exception do begin MemoLog.Lines.Add('Fehler in MachWas'); MemoLog.Lines.Add(E.ClassName+':'+E.Message); MemoLog.Lines.Add('Record: ' +IntToStr(Query1.RecNo); end; end; finally Query1.Next; // nächster Datensatz end; end; |
Re: Falsche Verwendung von try...except...end
@Sidorion: da hast du natürlich Recht, aber dein Lösungsvorschlag war nicht so gut.
Delphi-Quellcode:
Das Query1.Next ist nun an der richtigen Stelle; try..finally wird hier nicht benötigt.
// in folgendem Beispiel werden Daten aus einer Query gelesen
// Fehler werdem in einem Memo protokolliert und der Lesevorgang geht weiter // es werden keine Informationen unterdrückt, sondern die Fehlermeldungen werden protokolliert while not Query1.Eof do begin try MachWas(Query1); except on E:Exception do begin MemoLog.Lines.Add('Fehler in MachWas'); MemoLog.Lines.Add(E.ClassName+':'+E.Message); MemoLog.Lines.Add('Record: ' +IntToStr(Query1.RecNo); end; end; Query1.Next; // nächster Datensatz end; |
Re: Falsche Verwendung von try...except...end
Schon, aber Du weißt ja, wie das ist: In fünf Monaten macht da irgendwer ein raise; dran und dann wars wieder keiner ;)
|
AW: Falsche Verwendung von try...except...end
Die 5. Sünde ist Unfug (zumindest bei Delphi 6 - hab gerade keine andere Version parat).
Einen finally-Handler benötigt man nur, wenn man Exceptions nicht gesondert behandeln möchte. Selbstverständlich wird nach dem Except normal weitergemacht und eben nicht die Prozedur verlassen!
Delphi-Quellcode:
Beide ShowMessage werden ausgeführt.
procedure TForm1.Button1Click(Sender: TObject);
var a,b: double; begin try b := 0; a := 666; a := 10 / b; except ShowMessage('nulldivision'); end; ShowMessage(FloatToStr(a)); end; Ich weiß, dass dieser Thread alt ist, aber leider ist das der 3. Google-Treffer, wenn man nach Delphi-Exception sucht. Habe mich extra angemeldet in der Hoffnung, dass der Threadersteller seinen Eingangsbeitrag noch editieren könnte, damit nicht weiterhin diese Unwahrheit verbreitet wird. |
AW: Falsche Verwendung von try...except...end
Zitat:
|
AW: Falsche Verwendung von try...except...end
Und wenn in der Exception-Behandlung auch noch eine Problem auftritt, dann wird hier auch nichts mehr freigegen.
Dein ShowMessage kann auch aus verschiedenen Gründen zu einer Exception führen und dann war's das mit der Code-Ausführung danach. (Ja, ich geb zu, daß ich diese Art der Freigabe auch an einigen Stellen einsetze, aber in diesen Fällen hatte das A) seine Gründe (vorallem um noch ein paar Millisekündchen einzusparen, bei der Masse an Ausführungen) oder einfach nur wegen des kürzeren Codes und vorallem B) wußte ich, daß es in dieser Exceptionbehandlung garantiert zu keinem Problem kommen konnte (es sei denn es gibt so masive Probleme, daß das Programm sowieso gleich komplett verreckt wird). Aber in allen anderen Fällen kann ich ebenfalls nur die Freigabe über ein zusätzliches Try-Finally empfehlen. Vorallem da es so auch offensichtlicher wird, daß hier immer freigegeben, bzw daß dieser Code immer ausgeführt wird. |
AW: Falsche Verwendung von try...except...end
Zitat:
Zitat:
Zitat:
Vor allem hat es nichts mehr mit Sünde 5 von shmia zu tun. Dort ERSETZT finally einfach das except und die eigentliche Fehlerbehandlung fehlt. |
AW: Falsche Verwendung von try...except...end
Der try-finally-Block ist ja auch nicht dazu da um Exceptions zu behandeln.
Falls im try-Block eine auftritt, bleibt sie geworfen und wird weiterhin Ebene für Ebene hochgereicht bis sie behandelt wird.
Delphi-Quellcode:
Wenn man statt dem oberen try-finally ein try-except verwendet, wird die Exception ja abgefangen.
procedure Prozedur;
begin try TueWas; finally // Die Exception wird absichtlich nicht abgefangen. GebeResourcenFrei; end; end; ... try TueWas; Prozedur; TueWas; except // Denn sie soll HIER behandelt werden. on E: EChuckNorrisIsDead do begin ... end; end; Und das soll doch überhaupt nicht passieren. |
AW: Falsche Verwendung von try...except...end
Hallo,
ich habe mal eine Frage. Ist die Verwendung von try...except im folgenden Code richtig angewandt, bzw möglich:
Code:
Gruß Kieni
If WinVer.VersionText = 'Microsoft Windows XP' then
begin S:='Install .NET Framework 3.5'; WriteLog(S); try ExecuteCommand(installDir+'\dotNet3.5.exe',SW_SHOWNORMAL,true,nil,nil); S:='finished at ' + DateTimeToStr(Now); WriteLog(S); except on E:Exception do begin Writelog('Error while installing dotNet 3.5'); Writelog(E.ClassName+':'+E.Message); end; end; end; |
AW: Falsche Verwendung von try...except...end
Das ist richtig so: wenn das ExecuteCommand fehlschlägt, dann wird der Fehler mitgeloggt.
[edit] Nachtrag: das setzt natürlich voraus, dass im Fehlerfall auch wirklich eine Exception geworfen wird ;) [/edit] |
AW: Falsche Verwendung von try...except...end
Vielen Dank für den Beitrag shmia
|
AW: Falsche Verwendung von try...except...end
Ich will ja nicht kleinlich sein, aber:
Delphi-Quellcode:
Wenn
// in folgendem Beispiel werden Daten aus einer Query gelesen
// Fehler werdem in einem Memo protokolliert und der Lesevorgang geht weiter // es werden keine Informationen unterdrückt, sondern die Fehlermeldungen werden protokolliert while not Query1.Eof do begin try MachWas(Query1); except on E:Exception do begin MemoLog.Lines.Add('Fehler in MachWas'); MemoLog.Lines.Add(E.ClassName+':'+E.Message); MemoLog.Lines.Add('Record: ' +IntToStr(Query1.RecNo); end; Query1.Next; // nächster Datensatz end; end;
Delphi-Quellcode:
keine Exception auslöst, dann wird das hier ne Endlos-Schleife...
MachWas(Query1)
Delphi-Quellcode:
müsste ein
Query1.Next; // nächster Datensatz
Delphi-Quellcode:
weiter. Bitte korregieren oder ich hab da etwas falsch verstanden.
end
|
AW: Falsche Verwendung von try...except...end
Wie kommst Du darauf?
|
AW: Falsche Verwendung von try...except...end
Zitat:
|
AW: Falsche Verwendung von try...except...end
Oh, stimmt, das "end" zum "try" kommt ja erst danach.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz