![]() |
try .. except .. finally
Warum kann ich eigentlich wenn ich einen try benutze nicht einen except und ein finally verwenden?
Ich schreibe in eine Datei die auch schreibgeschützt sein kann, und dann kommt es zu einem Fehler. Ich würde gerne wenn es zu dieser Exception kommt eine Meldung in mein Logfile schreiben, aber dann trotzdem im finally das File wieder schließen. Momentan gehe ich einfach her und mache zwei try hintereinandern, mich würde nur interessieren ob mir jemand sagen kann warum try .. except .. finally als ganzes nicht geht?!?
Delphi-Quellcode:
var ppFile : TNativeXML; node : TXMLNode; begin try try ppFile := TNativeXml.CreateName('xyz'); node := ppFile.Root.NodeNew( 'test123' ); with node do begin WriteString( 'x', x); WriteInteger( 'y', y); end; except AddLogAlert( 'Fehler' ); end; finally ppFile.Free; end; end; |
Re: try .. except .. finally
Ist so weil darum könnte man jetzt einfach sagen. Sind eben zwei uterschiedliche Befehle. Da müsstest du dich auch fragen warm man bei Case nicht auch of und in gleichzeitig benutzen kann.
Gruß Stormy |
Re: try .. except .. finally
Hi,
stelle dir einfach die Frage: wofür brauchst du den finally-Block, wenn du ein try...except unmittelbar davor hast? Dadurch, dass alles davor abgefangen ist, wird das, was nach dem try...except-Block kommt, auf (fast) jeden Fall ausgeführt. Einzige Ausnahme: du hast im except-Teil wieder eine Exception. Gruß Michael [Edit]Zumal: deine Verwendung der try-Blöcke ist nicht ganz im Sinne des Erfinders: was passiert denn, wenn's bei ppFile := TNativeXml.CreateName('xyz') zu einer Exception kommt?[/Edit] |
Re: try .. except .. finally
Zitat:
|
Re: try .. except .. finally
Zitat:
Delphi-Quellcode:
So kannst du sicher gehen, dass auf jeden Fall der Speicher freigegeben wird, egal, was passiert.
begin
MySringList := TStringList.Create(); try //hier käme dann anderer Code finally MyStringList.Free(); end; end; Edit1: Kosmetik. Edit2: Das except ist im Endeffekt nur für Fehler, die du nicht selber abfangen kannst (z. B. bei falschen Rückmeldungen durch Server etc.). Gegen andere Dinge (Datei existiert, Datei zu groß/zu klein/nicht gültig) kannst du dich schützen. |
Re: try .. except .. finally
Hi,
So herum ist es richtig.
Delphi-Quellcode:
Ich frage mich allerdings noch immer, wozu du try except finally zusammen in einem Block brauchst. Nacheinander wird es doch sauber ausgeführt. Sehe da kein Problem. Das finally sollte in dem obigen Beispiel in jedem Fall ausgeführt werden.
[...]
begin ppFile := TNativeXml.CreateName('xyz'); try try [...] except AddLogAlert( 'Fehler' ); end; finally ppFile.Free; end; end; Edit: nur nochmal um es als Info zusammenzufassen: - finally dient dazu, einen Code in jedem Fall durchzuführen, zB zum Freigeben von Objekten - except dient dazu, Fehler abzufangen und zu verarbeiten Gruß Ansgar |
Re: try .. except .. finally
Zitat:
Delphi-Quellcode:
begin
ppFile := TNativeXml.CreateName('xyz'); try [...] except AddLogAlert( 'Fehler' ); finally ppFile.Free; end; end; |
Re: try .. except .. finally
kurz und knapp: Nein. Ich sehe aber auch keinen sinn darin...außer dich drei buchstaben zu sparen ;)
edit: in deinem Code oben hattest du die Erstellung des Objektes nach dem ersten try durchgeführt. Ist imho nicht ganz sauber, das sollte schon vor dem ersten "try" erzeugt werden. Nur darauf wollte ich mit meinem Codeschnipsel hinweisen :) |
Re: try .. except .. finally
Zitat:
Naja der Sinn darin wäre dass wenn ich z.B. beim schreiben in die Datei eine exception bekomme diese abfangen kann bzw. eine klare Fehlermeldung dazu ausgeben und ins logifle schreiben kann. Trotzdem will ich wenn die Exception kommt dass die Datei / Stringlist oder was auch immer definitive geschlossen wird. Das schließen soll aber natürlich auch wenn keine Exception kommt passieren (was ich normal im finally mache). Aber es ist ok, ich kann damit leben dass ich drei Zeichen mehr tippen muss :balloon: |
Re: try .. except .. finally
Zitat:
Ich kann Exception des gesamten Blockes auch noch später abfangen, also warum sollte es nun richtig sein den Except Block innerhalb des Finallys zu haben? Bitte gebe mir mindestens eine schlüssige Begründung dazu. Und wo wir gerade dabei sind an alle Leser nochmal ein Hinweis über einen gerne gemacht Fehler in diesem Zusammenhang:
Delphi-Quellcode:
In dieser Konstellation gibt Delphi keine Warnung aus, dass die Variable lFile möglicherweise nicht initialisiert worden ist.
var
lFile: TNativeXML; begin try lFile := TNativeXml.CreateName('xyz'); [...] finally FreeAndNil(lFile); end; end;
Delphi-Quellcode:
So rum schon.
var
lFile: TNativeXML; begin try lFile := TNativeXml.CreateName('xyz'); [...] finally lFile.Free; end; end; Der Fehler das Create in das try zu schieben wird oft und gerne gemacht. Auch ist die Frage der Anwendung des FreeAndNil() auf eine lokale Variable fraglich, aber FreeAndNil() ist besser und sicherer - steht an vielen Ecken. Damit wird es oftmals auch sehr oft eingesetzt. Im zweiten Falle kommt die Warnung von Delphi und es fällt auf, dass der Constructor Aufruf innerhalb des try/finally steht. Wenn aber nun FreeAndNil() verwendet wird, dann nicht. Hintergrund ist einfach nur, dass FreeAndNil() einen var Parameter und damit kann der Compiler dies nicht mehr erkennen, da die Funktion die Variable innerhalb ihrer belegen kann. FYI |
Re: try .. except .. finally
Hier mal meine Meinung:
Delphi-Quellcode:
:arrow: In so einem Fall braucht man das finally, da man ja Exceptions re-raisen kann ("Soll sich doch wer anderes damit rumschlagen")
begin
ppFile := TNativeXml.CreateName('xyz'); try try [...] except on e: EMySQLException do AddLogAlert('Fehler' + ppFile.ErrorMessage); on e: Exception do begin AddLogAlert('Fehler' + e.ErrorMessage); raise; end; end; finally ppFile.Free; end; end; :arrow: finally nach except, damit man im Except noch auf das Objekt zugreifen kann (und evtl. Infos heraauszuholen |
Re: try .. except .. finally
Zitat:
Ehrlich gesagt, fände ich es auch praktisch und lesbarer. Die Reihenfolge (erst except, dann finally) würde man nicht versehentlich verdrehen. Und wenn der Bereich Exceptionbehandlung eine Vereinfachung erhält, werden mehr Entwickler auf dieses Sprachfeature aufmerksam. Viele Entwickler nutzen Exceptions nicht und benutzen Returncodes zur Fehlerbehandlung (if MyFileSize < 0 then IrgendwasSeltsamesIstGeschehen). Cheers, |
Re: try .. except .. finally
Hi,
Zitat:
und später schreibst du: Zitat:
Grüße Ansgar |
Re: try .. except .. finally
Moin Zusammen,
um es mal allgemein zu schreiben (wenn man denn einen try/except-Block braucht:
Delphi-Quellcode:
Da es in dem konkreten Fall darum geht, dass eine Datei evtl. gesperrt ist, wäre es allerdings besser dies zu prüfen (z.B. durch den Versuch diese mit CreateFile exklusiv zu öffnen), und den Programmablauf an das Ergebnis der Prüfung anzupassen.
try
<Resource belegen> try <Mit der Resource arbeiten> finally <Resource freigeben> end; except <Ausnahme behandeln> end; Mit try/except sollte man nur dann arbeiten, wenn es wirklich nicht anders geht. |
Re: try .. except .. finally
@angos: Sorry, dann hatte ich das falsch verstanden, ich hatte das "richtig herum" auf die Verschachtelung except/finally bezogen.
Zitat:
|
Re: try .. except .. finally
Zitat:
Delphi-Quellcode:
var
SL: TStrings; S: string; begin try // Resource belegen SL := TStringlist.Create; try // Mit der Resource arbeiten S := SL[1]; finally // Resource freigeben FreeAndNil(SL); end; except // Ausnahme behandeln on E:Exception do begin ShowMessage(E.Message + Format(' - S hat %d Elemente', [SL.Count])); end; end; end; |
Re: try .. except .. finally
Das Problem was hier vorliegt: Du unterscheidest nicht, welche Exception aufgetreten ist. Du gehst in deinem Except Block fest davon aus, dass es ein Bereichsfehler/Indexfehler ist. Was aber wenn der Speichermanager das Create gar nicht durchführen konnte? Dann ist deine SL Variable so oder so im Eimer, egal wie rum except und finally stehen.
Grundlegend: Ich würde niemals mit Objekten in einem Exception Abschnitt arbeiten aus dem geschützten/umfassten Codebereich. Wenn gibt es Exceptions welche zusätzliche Informationen tragen bzw. tragen können. Aber ein Zugriff auf die Objekte aus dem geschützten Bereich im Exception - Behandlungsbereich ist nicht sicherer als innerhalb des Blockes. Eine Exception ist eine definitive Ausnahmesituation. Wenn bei dir die Küche brennt willst du dir bestimmt auch nicht vorher nochmal in Ruhe die Hände waschen bevor du dein Telefon anfässt um die Feuerwehr zu rufen - nur weil du es sonst auch immer machst (um dein Handy sauber zu halten). Wenn eine Ausnahmesituation auftritt, dann benutze verlässliche Quellen und das ist in diesem Falle die Exception selbst. Zitat:
|
Re: try .. except .. finally
Zitat:
Ob die Reihenfolge try ... finally ... except ... end oder try ... except ... finally ... end verwendet wird, macht daher schon einen Unterschied. C# und Java zum Beispel kennen nur try catch finally. Also erst "die Feuerwehr rufen", nicht als letztes. |
Re: try .. except .. finally
Moin Muetze,
Zitat:
Zudem dauert die Verarbeitung einer Exception IMHO relativ lange, und wenn man sich erst einmal daran gewöhnt hat alle möglichen Fehlerbedingungen nicht selber zu prüfen, könnte es sich auch negativ auf das Laufzeitverhalten auswirken. |
Re: try .. except .. finally
Zitat:
Manchmal ist eine Behandlung eines Fehlers auch nicht allgemeingültig möglich, z.B. wenn die gleiche Funktion mal in einer GUI, in einem Batchjob oder einem Webservice verwendet wird. Statt
Delphi-Quellcode:
kann man dann einfach die Exception werfen und die konkrete Anwendung der Funktion entscheidet, wie sie mit der Fehlersituation umgehen möchte.
if GUIVorhanden then Benutzerfragen ... else
|
Re: try .. except .. finally
Zitat:
Mal als Erweiterungsvorschlag einreichen... 8) |
Re: try .. except .. finally
Zitat:
SCNR |
Re: try .. except .. finally
Zitat:
TStringList hat nun nicht soviele mögliche Exceptions und eine Exception im Konstruktor wird von ihr soweit auch nicht verwendet, von daher ist es ein Beispiel gewesen. Es gibt genug Objekte in der freien Wildbahn welche weit andere Exceptions werfen. Und es nochmals daran erinnert, dass die einzige Möglichkeit einen Konstruktor abzubrechen das werfen einer Exception ist und somit hier nicht als Ding der Unmöglichkeit von der Hand zu weisen ist. Und wenn du QM so witzig findest, scheint dies bei dir/euch wohl auch genauso gehandhabt zu werden und somit ist die Frage was nach deren Prüfung am Ende heraus gegeben wird. Zitat:
Christian Seehase Wie der Name schon sagt, handelt es sich hier um eine Ausnahme, demzufolge finde ich es einfach sauberer mögliche Fehlerbedingungen selber zu prüfen, als es "drauf ankommen zu lassen", und die Programmsteuerung durch Exceptions zu regeln. Und da liegt der Hund begraben: persönliche Ansichten. Aber grundlegend hast du vollkommen Recht und ich stimme dir auch voll zu. Die Fehlerbehandlung darf durch die Nutzung der Exceptions nicht gänzlich entfallen, das ist der falsche Weg. Das habe ich so auch nie propagandiert. Eine Exception ist immer eine Ausnahmesituation, aber eine fehlgeschlagene Funktion ist dies noch lange nicht. Von daher ist die normale Fehlerbehandlung weiterhin wichtig und gefordert. Da sind wir uns auch komplett einig, von daher hast du mich vllt. falsch verstanden. Exceptions sind dazu gedacht auf Situationen hinzuweisen welche so nicht gedacht und/oder geplant waren. Wenn geplant war, dass eine Funktion fehlschlagen kann, dann kann sie ein entsprechenden negativen Rückgabewert o.ä. geben. Eine Exception hingegen weist auf eine ganz andere Situation neben den geplanten Abläufen hin. Wenn ich eine vom Benutzer ausgewählte Datei öffnen will, dann kann ich mit FileExists() prüfen ob diese existiert. Dann öffne ich sie und gehe auch davon aus diese benutzen zu können. Wenn diese aber durch einen anderen Prozess exklusiv geöffnet ist oder der Nutzer entgegen besseren Wissens uns eine schreibgeschützte Datei zum Speichern ausgewählt hat, so ist dies eine Situation die neben dem geplanten Ablaufstrang liegt. Diese Situation ist eine Exception wert und hier auch sinnvoll. Gerade dies Beispiel zeigt auf, dass man einfach nicht alles durch vorherige Abfragen abprüfen kann. Ich könnte neben FileExists natürlich noch die Attribute prüfen, aber nützt nichts, wenn ich die Datei aufgrund von fehlenden Rechten nicht öffnen kann. Nun gut, wenn ich Zeit habe erkenne ich noch das Dateisystem und checke dann die Rechte der Datei + Rechtekontext in dem die App läuft und dann ob ich damit die Datei öffnen kann. Bringt mir auch noch nichts, wenn ein anderer Prozess diese Datei hat. Ok, also das auch noch abprüfen und dann habe ich ein Problem, wenn der Nutzer auf eine Netzwerkfreigabe gegangen ist, etc, etc, etc. Grüsse, Muetze1 |
Re: try .. except .. finally
Zitat:
Cheers, |
Re: try .. except .. finally
Zitat:
Und gerade dadurch wird die Kernfrage doch schon geklärt: Wenn du Dinge aus dem inneren Block nutzen willst, dann muss der Except Block innerhalb von finally stehen. Wenn aber nicht, dann lieber ausserhalb, weil sonst die Gültigkeit der lokalen Daten welche mit finally definitiv freigegeben werden sollen, unnötig verlängert wird. |
Re: try .. except .. finally
Moin Muetze,
Zitat:
Du wolltest ja nur eine Begründung habe, warum ich der Ansicht bin, dass man Exceptions nur Ausnahmsweise verwenden sollte ;-) @Michael: Schon klar, dass eine nicht ausgelöste Exception das Programm nicht verlangsamt. Ich habe nur schon gesehen, dass diese intensiv benutzt werden um, oft simple, Prüfungen zu ersetzen, so dass die Exceptions recht häufig geworfen werden, und dann kann es sich durchaus als Bremse erweisen. |
Re: try .. except .. finally
Dass ich jetzt so eine Diskussion vom Zaun breche wollte ich nicht, also vertragt Euch wieder :kiss:
Zitat:
Das was Muetze1 beschrieben hat trifft bei mir exakt zu, ich prüfe natürlich mit FileExists ob die Datei auch wirklich da ist, öffne Sie dann und versuche dann meine Daten zu schreiben. Die Datei gibt es auch, aber der User hat keine Rechte auf dem Pfad und ich kann die Datei zwar öffnen, aber eben nicht den Inhalt schreiben. Mir war es nun genau zu viel Aufwand hier sämtliche Dinge zu prüfen, da es sich sowieso um eine Ausnahmesituation handelt wollte ich das als Excpetion abfangen. Ich komme ansonsten halt vom 100ten ins 1000ste und bin nur noch am prüfen und machen bevor ich zum eigentlichen Sinn meiner Software komme. Meine Frage war ja auch nur warum ich keinen try .. except .. finally Block machen kann, weil mir das in diesem Moment einfach logisch erschien. Ich habe aber nun verstanden dass die Syntax das eben nicht vorsieht :cheer: |
Re: try .. except .. finally
Wir hatten schon diverse Diskussionen zum Thema 'Exceptions: Geißel oder Segen?'. Oder auch: 'Oute ich mich als Versager, wenn ich mit Try..Except arbeite'.
Ich werde mal wieder meine Meinung zum Besten geben: Ein Grundsatz robuster Softwareentwicklung ist, das innere Exceptions nicht nach außen dringen sollen. Ich muss also *alle* Exceptions abfangen, behandeln und ggf. in andere Exceptions übersetzen. Jede öffentliche Klasse sollte auch einen Satz von eigenen Exceptions mitbringen, in die die inneren Exceptions ggf. übersetzt werden. Was bringt dem Anwender eine Exception der TCP-Klasse? Er versteht sie nicht, er wollte mit TCP nix am Hut haben, also: Gar nichts. Ihm ist es auch egal, das der Programmierer einen SQL-Befehl falsch geschrieben hat. Er will klare und verständliche Fehlermeldungen. in der Logdatei kann der Fehler ja stehen, aber nicht auf dem Bildschirm. Für mich (und u.A. auch die Erfinder moderner Programmiersprachen) sind Try-Except Blöcke ein Segen, denn sie erlauben mir, einen klaren Programmfluss, der eben nicht durch ständige Abfragen von Präkonditionen unleserlich gemacht wird. Denn Eine Exception ist die Ausnahme, der Code wird also i.d.R. so abgearbeitet, wie ich es wollte, nur eben in Ausnahmen nicht. Die sind i.d.R. gravierend und führen dann zum Abbruch der Aktion. D.h. natürlich nicht, das ich auf sämtliche Präkonditionen verzichte, aber da ich sowieso nicht alle Fehler von vorne herein abfangen kann, beschränke ich mich auf die, die den Code leserlicher machen. Beispiel: Ich kann schauen, ob eine Datei, aus der ich lesen will, existiert. Aber wozu soll ich vorher prüfen, ob die Datei korrupt ist? Da lass ich den Karren doch lieber an die Wand fahren und kratze die überbleibsel ab und analysiere sie. Gut, Try-Except macht also Sinn. Alle sichtbaren Methoden sind mit einem Try-Except-Block gekapselt, und sei es, um die Logdatei zuzumüllen. Das ich zudem in den meisten Methoden irgendwelche Klassen instantiiere, die ich im Finally-Block wieder freigebe, folgt daraus, das alle Methoden nach dem Motto: Reservieren-Ausführen-Fehler behandeln-Freigeben implementiert werden.
Delphi-Quellcode:
Ist hübsch aber überflüssig, denn der Fehler wird nicht weitergereicht, also braucht man auch den Finally-Block nicht.
Try
... Except LogDenFehler; Finally // << --- unnötig WaschDieHände; End; Ich konvertiere Fehler und leite sie weiter, denn Fehler sind schwerwiegend und keine Bagatelldelikte. Also wäre mir ein kompakter Try-Except-Finally-Block angenehm.
Delphi-Quellcode:
Ich nehme mal an, die Java- und C#-Erfinder haben sich so etwas ähnliches dabei gedacht, also sie die kombinierten Try-Catch-Finally-Blocke ins Sprachkonzept aufgenommen haben. Das sie bei Delphi fehlen, ist schade, aber es gibt Schlimmeres.
Try
... Except LogDenFehler; LeiteIhnWeiter; // <<--- Finally WaschDieHände; End; |
Re: try .. except .. finally
Zitat:
Nachdenkliche Güße GreenHorn |
Re: try .. except .. finally
wenn in AddLogAlertein Fehler auftritt, dann wird ppFile immernoch freigegeben
und danach die Exception von AddLogAlert nach außen weitergereicht. |
Re: try .. except .. finally
Die Methode AddLogAlert hat natürlich einen eigenen Exception-Handler, der etwaige Probleme abfängt. Was interessiert den Programmierer, ob die Platte korrupt ist? Das muss die IO-Schicht abfangen und ggf. eine fatale Exception werfen, oder im Hintergrund eine neue Festplatte downloaden und sofort installieren. :stupid:
Hier ist uns Java überlegen, wo man in der Methodendeklaration gleich noch angibt, welche Exceptions auftreten können. |
Re: try .. except .. finally
Zitat:
![]() Dort wird auch genannt, warum ich keine große Notwendigkeit für try-except-finally sehe: Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:55 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 by Thomas Breitkreuz