Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Frage zu try..except
AScomp - Di 05.01.10 07:51
Titel: Frage zu try..except
Guten Morgen,
mit try..except kann ich im Normalfall ja das Auslösen bzw. die Anzeige von Exceptions verhindern. Bisher ging ich davon aus, dass
Delphi-Quelltext
1: 2: 3: 4:
| try bla; except end; |
wirklich ALLE möglicherweise beim Aufruf von "bla" auftretenden Exceptions abgefangen werden und der Programmablauf nicht abgebrochen wird.
In einem anderen Forenbereich hatte ich jetzt von einem Problem mit folg. Sourcecode berichtet:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| try if CreateLogfile then begin AssignFile(LogDatei, AppDataDir + 'mk.log'); if FileExists(AppDataDir + 'mk.log') then Append(LogDatei) else ReWrite(LogDatei); WriteLn(LogDatei, Info); end; finally try CloseFile(LogDatei); except end; Application.ProcessMessages; end; |
Trotz try..finally wurde nämlich beim Aufruf von "Append(LogDatei)" eine Exception ausgelöst, die von madExcept behandelt wurde.
Inzwischen hab ich die entsprechenden, möglicherweise auftretenden Exceptions in obigem Sourcecode durch den Schalter {$I-} erstmal deaktiviert.
Dann noch folgender Fall:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| try FormProgress.VCLZipVerify.ReadZip; FormProgress.VCLZipVerify.CheckArchive; except On EUserCanceled do ExecutionCancelled := true; end; |
Ich ging bisher anscheinend fälschlicherweise davon aus, dass mit diesem Sourcecode alle Exceptions abgefangen werden und nur im Falle der Exception EUserCancelled die Variable noch auf true gesetzt wird.
Doch anscheinend ist das falsch. Der obige Sourcecode fängt nur eine einzige Exception ab, eben EUserCancelled. Alle weiteren Exceptions bleiben unbehandelt und werden normal ausgegeben. Um das zu verhindern, müsste ich wohl den Sourcecode wie folgt abändern:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| try FormProgress.VCLZipVerify.ReadZip; FormProgress.VCLZipVerify.CheckArchive; except On EUserCanceled do ExecutionCancelled := true; else end; |
Doch was heißt das jetzt genau für:
Delphi-Quelltext
1: 2: 3: 4:
| try bla; except end; |
Heißt das, dass in diesem Beispiel ALLE Exceptions abgefangen werden (da im except-Abschnitt keine Exception explizit behandelt wird)? Und würde sich das Verhalten ändern, sobald ich im except-Abschnitt ein on EIrgendwas do einfüge (nämlich derart, dass nur noch diese eine Exception abgefangen wird, während alle anderen unbehandelt bleiben und entsprechend auch vom Programm ausgegeben werden?)?
Danke schonmal, falls jemand meinen Ausführungen überhaupt folgen konnte - wurde ja ein richtiger Roman. ;)
Delete - Di 05.01.10 10:46
AScomp hat folgendes geschrieben : |
Doch was heißt das jetzt genau für:
Delphi-Quelltext 1: 2: 3: 4:
| try bla; except end; |
Heißt das, dass in diesem Beispiel ALLE Exceptions abgefangen werden (da im except-Abschnitt keine Exception explizit behandelt wird)? Und würde sich das Verhalten ändern, sobald ich im except-Abschnitt ein on EIrgendwas do einfüge (nämlich derart, dass nur noch diese eine Exception abgefangen wird, während alle anderen unbehandelt bleiben und entsprechend auch vom Programm ausgegeben werden?)? |
Ja. Allerdings ist es keine gute Idee Exceptions nicht zu behandeln. Ist ungefähr so, als wenn du im Auto die Tankanzeige ausbaust.
AScomp - Di 05.01.10 12:32
Das ist soweit klar - danke!
jakobwenzel - Di 05.01.10 15:19
AScomp hat folgendes geschrieben : |
| Trotz try..finally wurde nämlich beim Aufruf von "Append(LogDatei)" eine Exception ausgelöst, die von madExcept behandelt wurde |
Das soll auch so, try...finally ist dazu da um etwas (beispielsweise das Freigeben von Objekten) auch dann durchzuführen wenn eine Exception auftrat. Gefangen wird die Exception nur im try...except.
AScomp - Di 05.01.10 15:34
jakobwenzel hat folgendes geschrieben : |
AScomp hat folgendes geschrieben : | | Trotz try..finally wurde nämlich beim Aufruf von "Append(LogDatei)" eine Exception ausgelöst, die von madExcept behandelt wurde |
Das soll auch so, try...finally ist dazu da um etwas (beispielsweise das Freigeben von Objekten) auch dann durchzuführen wenn eine Exception auftrat. Gefangen wird die Exception nur im try...except. |
Sicher? Ich bezweifle, dass es so ist. Im Beitrag
http://www.delphi-forum.de/topic_AssignFile+und+tryfinally_96919.html kam das auch so rüber, als ob finally eher die Exception "schlucken" würde.
Demzufolge müsste man dann except und finally auch gemeinsam nutzen können.
Also beispielsweise sowas:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| try if CreateLogfile then begin AssignFile(LogDatei, AppDataDir + 'mk.log'); if FileExists(AppDataDir + 'mk.log') then Append(LogDatei) else ReWrite(LogDatei); WriteLn(LogDatei, Info); end; except finally try CloseFile(LogDatei); except end; Application.ProcessMessages; end; |
Sprich: Wenn im try-Abschnitt eine Exception auftritt, soll diese "geschluckt" werden und der finally-Abschnitt abgearbeitet werden.
JDF - Di 05.01.10 15:54
Hi,
| Zitat: |
| Demzufolge müsste man dann except und finally auch gemeinsam nutzen können. |
ist eine schöne Idee, andere Programmiersprachen können das.
Im Delphi kenne ich nur die Schachtelung von try..except und try..finally.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure Test; begin TRY Objekt.Erstellung; TRY TRY Objekt.Nutzung; EXCEPT Objekt-Anhängige Fehlerbearbeitung; END; FINALLY Objekt.Beendigung; END; EXCEPT Objekt-Unabhängige Fehlerbearbeitung; END; end; |
Ohje, der Konstrukt sieht schlimm aus.
Gruß
Jürgen
AScomp - Di 05.01.10 16:04
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| TRY TRY Objekt.Nutzung; EXCEPT Objekt-Anhängige Fehlerbearbeitung; END; FINALLY Objekt.Beendigung; END; |
Ich meine, dass das try..finally hier überhaupt keine Wirkung hat. Genauso gut hätte man doch folg. machen können:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| TRY Objekt.Nutzung; EXCEPT Objekt-Anhängige Fehlerbearbeitung; END; Objekt.Beendigung; |
Bzw. falls im except nicht alle möglichen Exceptions abgefangen werden:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| TRY Objekt.Nutzung; EXCEPT Objekt-Anhängige Fehlerbearbeitung; ELSE END; Objekt.Beendigung; |
jakobwenzel - Di 05.01.10 16:10
Wenn hier aber in der Objekt-Anhängigen Fehlerbearbeitung nochmal ne Exception auftritt hast du ein nicht freigegebenes Objekt.
AScomp - Do 11.03.10 20:42
Hallo,
hätte nochmal eine Frage hierzu:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function _GetFileSize(const FileName: string): Int64; var FileStream: TFileStream; begin Result := -1; try try FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone); Result := FileStream.Size; except end; finally try FileStream.Free; except end; end; end; |
Geht das nicht einfacher?
Ein
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| try .. except .. finally .. end; |
gibt's ja anscheinend nicht.
Wie löse ich also obige Mini-Funktion sauber?
Das try..finally bräuchte ich ja eigentlich nicht, da ich die Exceptions ohnehin fange und der zweite try..except-Block somit ja in jedem Fall aufgerufen wird, richtig?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| function _GetFileSize(const FileName: string): Int64; var FileStream: TFileStream; begin Result := -1; try FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone); Result := FileStream.Size; except end; try FileStream.Free; except end; end; |
Sieht auch nicht viel besser aus.
Vielen Dank!
BenBE - Do 11.03.10 20:58
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function _GetFileSize(const FileName: string): Int64; var FileStream: TFileStream; begin Result := -1; try FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone); try Result := FileStream.Size; finally FileStream.Free; end; except end; end; |
AScomp - Do 11.03.10 21:13
Danke dir, das hatte ich auch schon - was mich stört ist, dass es zwei try-Blöcke sind.
Aber da es keine try..except..finally-Blöcke zu geben scheint, wird das wohl die einzige Möglichkeit sein.
Delete - Do 11.03.10 21:24
BenBE hat folgendes geschrieben : |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function _GetFileSize(const FileName: string): Int64; var FileStream: TFileStream; begin Result := -1; try FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone); try Result := FileStream.Size; finally FileStream.Free; end; except end; end; | |
Was soll der äußere try-except-Block? Und was sagt der Delphi Compiler dazu?
Richtig wäre:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Objekt erstellen try try mit Objekt arbeiten except Excpetions behandeln end finally Objekt freigeben end |
AScomp - Do 11.03.10 21:29
Warum? Ich möchte ja, dass keine Exception angezeigt wird.
Wenn in deinem Beispiel der FileStream nicht erstellt werden kann, wird trotzdem der finally-Abschnitt aufgerufen und versucht, den FileStream wieder freizugeben.
Delete - Do 11.03.10 21:46
dann so rum:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| try <Resource belegen> try <Mit der Resource arbeiten> finally <Resource freigeben> end; except <Ausnahme behandeln> end; |
Aber was für ein Grund gibt es einen aufgetretenen Fehler unterdrücken zu wollen? Der Benutzer wäre über eine aussagekräftige Fehlermeldung bestimmt sehr erfreut, als einfach so im dunklen stehen gelassen zu werden und eventuell einen Datenverlust zu erleiden.
AScomp - Do 11.03.10 21:51
Dass ich die Exception DORT nicht abfange heißt ja nicht, dass sie überhaupt nicht abgefangen wird. Nur eben nicht an dieser Stelle. ;)
So hat es BenBe doch vorgeschlagen, oder entgeht mir schon wieder was? :D
Delete - Do 11.03.10 22:10
Mist, stimmt. Ich schiebe das jetzt mal auf meine Kopfschmerzen.
AScomp - Do 11.03.10 22:11
Gute Besserung!
BenBE - Fr 12.03.10 01:23
@Luckie: Die Fehlerbehandlung wird in dieser Routine basierend auf dem Result erledigt. Sauberer wäre es aber mit CreateFile die Datei zu öffnen und über das Handle wenn möglich einen THandleStream aufzubauen. Wobei man für diesen Fall auch gleich komplett über die WinAPI gehen könnte, was sogar die Nutzung einer Exception hier ganz vermeidet ...
P.S.: Sollte man schlafen gehen, wenn man im vorigen Post "Gute Bescherung" liest?
Martok - Fr 12.03.10 03:34
Die Kombination CreateFile/GetFileSizeEx/CloseHandle ist an der Stelle tatsächlich vorzuziehen.
Allein schon, weil man dann volle Kontrolle über Fehlercodes hat, und außerdem um den Aufwand der Klasseninstantiierung herum kommt.
P.S.: Ja, direkt bis zum Dezember durchschlafen...
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!