![]() |
Wichtigkeit von Try...Finally...End
Hallo Ihr alle,
ich wollte euch einmal mitteilen, wie dermaßen wichtig der richtige Gebrauch von try...finally-Blöcken seien kann. Bei mir im Programm sind beim Öffnen eines Dialoges plötzlich Zugriffsverletzungen aufgetreten. Aber erstens nur auf einem System, auf dem BDS2006 nicht installiert ist - in der IDE hat sich nichts getan, daher war debuggen nicht möglich und außerdem nur manchmal. Zunächst unerklärlich. Bis ich dahinter gekommen bin, dass sie immer dann auftreten, wenn ich vorher eine bestimmte Aktion gemacht habe. Nach stundenlanger (ich habe seit heute Nachmittag 15 Uhr danach gesucht) Suche habe ich folgendes böses Stück Code gefunden: :coder2:
Delphi-Quellcode:
Ich bin davon ausgegangen, dass dieser Progress-Dialog wohl keinen Schaden anrichten wird. Pustekuchen! Irgendwas hat er bewirkt. Ich denke, dass das ADODataSet nicht zerstört wurde, was dann irgendwann (immernoch unerklärlich :gruebel: ) zu Schutzverletzungen geführt hat.
ADODataSet := pLogicDataModule.GetADODataSet('SELECT ID FROM MD_InvoiceRules WHERE Active = 1 ORDER BY Mandator', true);
try ProgressDialog := TJvProgressDialog.Create(NIL); ProgressDialog.ScreenPosition := poMainFormCenter; ProgressDialog.Caption := 'Rechnungserstellung'; ProgressDialog.Text := 'Verarbeite Regeln (insgesamt '+IntToStr(ADODataSet.RecordCount)+')'; ProgressDialog.Show; ProgressDialog.Position := 0; ProgressDialog.Min := 0; ProgressDialog.Max := ADODataSet.RecordCount; ProgressDialog.ShowCancel := False; while not ADODataSet.Eof do begin ProcessInvoiceRule(ADODataSet.FieldByName('ID').AsInteger, AccountingPeriod); ADODataSet.Next; ProgressDialog.Position := ProgressDialog.Position+1; end; finally ProgressDialog.Free; ADODataSet.Free; end; Eine Änderung in folgendes, hat den Fehler eliminiert:
Delphi-Quellcode:
Eines habe ich daraus gelernt: Spare nicht noch einmal an Try-Finally-Blöcken. :spin2:
ADODataSet := pLogicDataModule.GetADODataSet('SELECT ID FROM MD_InvoiceRules WHERE Active = 1 ORDER BY Mandator', true);
try ProgressDialog := TJvProgressDialog.Create(NIL); try ProgressDialog.ScreenPosition := poMainFormCenter; ProgressDialog.Caption := 'Rechnungserstellung'; ProgressDialog.Text := 'Verarbeite Regeln (insgesamt '+IntToStr(ADODataSet.RecordCount)+')'; ProgressDialog.Show; ProgressDialog.Position := 0; ProgressDialog.Min := 0; ProgressDialog.Max := ADODataSet.RecordCount; ProgressDialog.ShowCancel := False; while not ADODataSet.Eof do begin ProcessInvoiceRule(ADODataSet.FieldByName('ID').AsInteger, AccountingPeriod); ADODataSet.Next; ProgressDialog.Position := ProgressDialog.Position+1; end; ProgressDialog.Hide; finally ProgressDialog.Free; end; finally ADODataSet.Free; end; Das wollte ich einfach mal erzählt haben :dancer: Viele Grüße, Dominik |
Re: Wichtigkeit von Try...Finally...End
Zitat:
|
Re: Wichtigkeit von Try...Finally...End
Das was Dominik hier erwähnt ist in der Tat keine "läppische" Angelegenheit!
Das Auffangen von Fehlern mit Try..Except bzw. Try..Finally ist besonders wichtig wenn man wirklich sicher gehen will Objekte, die man erstellt hat, auch wieder freizugeben! Denn sonst läuft Speicher voll und bereits gelöscht geglaubte Daten werden von neuen Objekten in Anspruch genommen und schwupps hat man einen Fehler oder noch schlimmer: einen Absturz! :o Ich kenne einige Programmierer die Objekte erstellen und dann unten irgendwann mal mit FREE wieder freigeben. Ohne sie im TRY..EXCEPT oder TRY..FINALLY Konstrukt verpackt zu haben. Wenn ich sie frage, warum sie das nicht machen heißt es: "Das ist nur unnötige Tipparbeit!..." oder "Warum soll da was passieren? Das läuft garantiert durch und wird später wieder freigegeben..." Naja jeder wie ers will. Aber für mich gilt: Egal ob ein Formular dynamisch mit Application.CreateForm, oder ein Objekt erstellt wird was später wieder DESTROY't oder GEFREE't werden soll, TRY..FINALLY muss mindestens mit! :angel: Gruß FlatCoder :bounce1: |
Re: Wichtigkeit von Try...Finally...End
Könnte auch ein Argument sein, Factories (wie getAdoDataSet) Interface instanzen zurückgeben zu lassen. Dadurch kümmert sich der Compiler um Try-finally und man spart sich Tipperei. :zwinker:
btw, dein Problem verstehe ich trotzdem nicht ganz. Das Freigeben des DataSets hätte doch nur duch eine Exception im Destructor vom ProgressDialog verhindert werden können. Die wiederum hätte dir doch auffallen müssen.... :gruebel: |
Re: Wichtigkeit von Try...Finally...End
Bitte mal auf Deutsch! Ich verstehe gar nix.
|
Re: Wichtigkeit von Try...Finally...End
Zitat:
Ich bin mir zwar nicht sicher, aber ich meine, bei try..finally wird bei einer Exception im finally-Block auch aus dem finally-Block herausgesprungen, bevor er vollständig abgearbeitet ist. Das wäre die einzige plausible Erklärung, die ich so ohne weiteres wüsste, ohne mich nochmal damit beschäftigen zu müssen, was Delphi da anstellt. Und Exception-Handling ist performancetechnisch so billich, da kann man lieber mal eins zu viel nehmen als eins zu wenig. |
Re: Wichtigkeit von Try...Finally...End
Zitat:
![]() Interface ist dir hoffentlich geläufig :wink: . |
Re: Wichtigkeit von Try...Finally...End
Zitat:
Zitat:
Delphi-Quellcode:
stehen. Das sollte ja eigentlich die Exception rauslassen. Das komische ist halt, dass es in der Delphi-Umgebung alles funktioniert. Daher erhalte ich da auch keine Exception. Die kommt aber "wie erwartet" auf einem System ohne Delphi.
...
except // Rollback the transaction on error pLogicDataModule.DBConnection.RollbackTrans; raise; end; Einen Fehler in der RTL schließe ich eigenltich aus - der Konstruktor funktioniert einwandfrei: Mein ProgressDialog wird wie gewollt angezeigt. Evtl. geht es schief, wenn ich diesen Dialog freee, ohne ihn vorher versteckt zu haben. Aber das möchte ich nicht auch noch testen - der Fehler hat mich genug Zeit gekostet ;-) |
Re: Wichtigkeit von Try...Finally...End
Zitat:
Dann würde es mich ja schon mal interessieren, was denn da schief läuft. Schade, daß du keinen Nerv zu hast, das zu debuggen, aber vielleicht findest du die Neugier ja am Wochenende wieder ;-) |
Re: Wichtigkeit von Try...Finally...End
Zitat:
Delphi-Quellcode:
Wenn der Dialog angezeigt wurde, und man ihn ohne vorheriges Verstecken zerstören möchte, dann bleibt das Fenster am Leben. Hier schafft ein "Hide" vor dem ersten FreeAndNil Abhilfe.
destructor TJvProgressDialog.Destroy;
begin FreeAndNil(FImage); FreeAndNil(FIImage); inherited Destroy; end; Allerdings erklärt das mein spezifisches Problem nicht. Mein Problem tritt ja auch nicht da - sondern ein paar hundert Zeilen später - in einem ganz anderen Modul auf. Und das ohne das ich noch einmal diesen ProgressDialog verwende. Das ganze bleibt mir ein Rätsel. :cyclops: Aber immerhin konnte ich so jetzt einen kleinen JVCL-Fehler verbessern :-) Hat ja auch was! Weiteres Debuggen werde ich nicht machen - zumal sich dieser Fehler ja auch nicht debuggen lies. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:35 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