![]() |
Verständnisfrage zu try-except-finally
Hallo an alle DPler,
Hab eine Frage zu try-except-finally. Also ich habe schon sehr erfolgreich try-except-Abfragen in meinem Projekt eingebaut und alles lief wunderbar. Hier mal ein kleines Beispiel:
Delphi-Quellcode:
Sind ein paar Funktionen für ein Controler-Board und wie gesagt, bin sehr zufrieden damit. Jetzt versuche ich in meiner Komponente ebenfalls eine try-except-Abfrage zu machen und bekomme trotz das ich den eigentlichen Fehlerpunkt damit "umschließe" immer eine Fehlermeldung und ich weiß einfach nicht, warum dies der Fall ist.
function TControlerBoard.anaAusgang_einschalten: boolean;
begin try if sKameraposition = 'oben' then begin OutputAnalogChannel(1,Diodenhelligkeit[1]); anaAusgang_ausschalten(2); end else begin OutputAnalogChannel(2,Diodenhelligkeit[2]); anaAusgang_ausschalten(1); end; result := true except // Fehlermeldung result := false; end; end; function TControlerBoard.anaAusgang_ausschalten(iNummer: Integer): boolean; begin try ClearAnalogChannel(iNummer); result := true except // Fehlermeldung result := false; end; end; function TControlerBoard.alle_anaAusgeange_ausschalten; begin try ClearAllAnalog; result := true except // Fehlermeldung result := false; end; end; Hier meine derzeitige Routine an der ich arbeite.
Delphi-Quellcode:
Hab die Stelle markiert, wo der Fehler auftreten kann. Eigentlich, so aus meinem Verständnis heraus, sollte das Programm, wenn dWert nicht eine Gleitkomma-Zahl übergeben wird in die Except-Fkt springen und mir somit ein "Hier" ausgeben. Er meldet mir aber, dass in dem Edit (FEdmanuelleBeschleunigungsEingabe) dies nicht der Fall ist (es steht dort wirklich keine Gleitkomma drin!) was also richtig ist. Wie gesagt, eigentlich erwarte ich eigentlich, dass die Exception nicht auftritt und er mir statt dessen Die Showmessage zeigen sollte.
procedure TContainer.Beschleunigungmanuellverlassen(Sender: TObject; var Key: Word;
Shift: TShiftState); var Index: integer; dWert: double; begin if Key = 13 then begin try dWert := strtofloat(FEdmanuelleBeschleunigungsEingabe.Text) // <-- Hier tritt der Fehler auf except Showmessage('Hier'); end; end; end; Kann mir das jemand mal erklären, warum dies in dem Fall so ist? PS.: ich weiß mit der trystrtofloat könnte ich dieses ganze Problem umgehen, indem ich eine if-Abfrage starte aber wenn ich dies tun würde, dann wäre die try-Except-Abfrage in meinem bisherigen Verständnis der Problematik überflüssig, da ich alles mit if abfragen abfangen kann (in einem gewissen größeren Rahmen sicherlich). Vielen Dank BAMatze |
Re: Verständnisfrage zu try-except-finally
Kann es sein, dass du unter Tools --> Debugger-Optionen --> Sprach-Exceptions die Option "Bei Delphi-Exceptions stoppen" aktiviert hast und die Anwendung aus der IDE heraus startest?
Hans. |
Re: Verständnisfrage zu try-except-finally
Ergänzung zu roter Kasten:
Du hast aber nicht übersehen, dass beim ausführen des Programmes in der IDE das Programm immer bei jedem Fehler angehalten wird. Erst danach erfolgt eine mögliche Excpetionbehandlung. Also: Innerhalb der IDE kommt erst der Stop beim Fehler selbst und dann was in Except steht. Außerhalb der IDE passiert nur, was in Except steht. |
Re: Verständnisfrage zu try-except-finally
Wer dir hier die Exception meldet, ist der Debugger ... starte mal dein Programm außerhalb der Delphi-IDE oder schalte die entsprechenden Meldungen ab.
aber zumindestens im Fertigen Programm (ohne daß es im Debugger läuft) wird die Exception nicht mehr angezeigt. PS: TryStrToFloat hätte noch einen Vorteil, denn dieses wirft erst garkeine Exception, welcher sich erstmal durch's halbe Programm frißt (Exceptions sind 'ne größere Angelegenheit und da läuft einiges im Hintergrund ab, welches natürlich auch Rechenzeit frißt und dazu noch den Code etwas vergrößert) |
Re: Verständnisfrage zu try-except-finally
Ja das Häckchen war es.
Wäre aber jetzt eine Folgefrage: Was sollte man wo setzen? Ich meine in diesem Fall würde ich warscheinlich die trystrtofloat-Abfrage bevorzugen, da ich aufgrund der Kürze des Programmcodes mit keinen weiteren Fehlern rechnen müsste (Der Fehler ist somit qualifizierbar). Gibt es da vieleicht (für einen Anfänger wie mich) so grundsätzliche Regeln für den Einsatz von try-except-finally, die zu einer gewissen Warscheinlichkeit immer greifen, so dass man nur noch die Ausnahmen behandeln muss oder ist das eher eine Philosophy, die sich ein jeder Programmierer oder Benutzer einer Programmiersprache selber erfinden muss? |
Re: Verständnisfrage zu try-except-finally
Du benützt try..except auf eine ganz falsche Art und Weise!!
Früher, als es noch keine Exceptions gab, hat man Fehler fast immer über einen Returncode zurückgeliefert.
Delphi-Quellcode:
Man kann dies noch etwas vereinfachen, in dem man als Returncode nur True oder False zurückliefert.
function BerechneIrgendwas:integer;
begin ... if zins < 0.0 then begin result := ERROR_CODE_ZINS_FALSCH; Exit; end; ... end; Natürlich ist die Technik einen Fehler über einen Boolean zurückzumelden (so wie du das in TControlerBoard.anaAusgang_einschalten tust) das Schlechteste was man tun kann. Grund: die Ursache des Fehler bleibt für immer im Dunkeln Und jetzt kommt die Technik der Exceptions in Spiel. Jetzt man man sinnvolle Fehlermeldungen zurückliefern, anstatt nur Fehlercodes oder nur die Info "Geht" oder "Geht nicht". Richtig blöd wird es aber, wenn man eine Exception mit sinnvoller Fehlermeldung (z.B. "COM-Port 1 kann nicht geöffnet werden") mit try...except abfängt und daraus einen Boolean-Returncode produziert. :wall: Weiterer Lesestoff: ![]() |
Re: Verständnisfrage zu try-except-finally
also wenn dein Programm nach der Exception noch 'ne Weile ordentlich weiterlaufen soll, dann dort, wo du etwas schützen mußt >>> Resourcenschutzblock
Delphi-Quellcode:
oder wenn du selber auf die Exception reagieren willt, um stattdessen etwas Alternatives zu machen
// hier Speicher reservieren / etwas sperren oder sonstwas,
// was auf jeden Fall rückgängig gemacht werden muß Lock; oder X:=GetMem; oder Y:=Z.Create; try //hier was machen finally // und hier den Speicher freigeben oder die Sperre aufheben Unlock; oder FreeMem(X); oder Y.Free; end;
Delphi-Quellcode:
Es ist garnicht möglich wirklich auf alles zu reagieren, also besinn dich nur auf das "Nötigste", dann bleibt dein Code auch übersichtlicher.
try
// mach was except // mach stattdessen was Anderes end; in nochmalen VCL-Anwendungen (nicht in einer Konsolenanwendung) ist eh nahezu jeder Prozeduraufruf seitens der VCL (also z.B. Ereignisprozeduren) mit einem Try-Except abgesichert, so daß nicht gleich das ganze Programm verreckt, wenn mal was passiert. :angel: PS: in meinem aktuellen Projekt ( ![]() Ich sorge meist nur mit einem Try-Finally daß möglichst keine Speicherlecks entstehen. (kannst dich da gern mal umsehen) So kann man im aufrufendem Code besser reagieren und man erfährt auch was und wo es geknallt hat ... denn wenn es knallt, dann hat das 'nen Grund und den gilt es zu finden und zu beheben, anstatt alles unter den Teppisch zu kehren. :angel2: PSS: meinen ![]() |
Re: Verständnisfrage zu try-except-finally
Also schonmal ein Dankeschön an shmia und himitsu für die doch recht ausführlichen Erklärungen über try Except.
@shmia Ich hab mir deinen Lesestoff mal zu Gemüte geführt und es ist auch sehr informativ. Habe auch glaube ich ein paar Prozeduren genommen, wo ich für mich selber festgestellt habe, dass auch wenn die Aufrufe ins Nirvana gehen (z.B. wenn die Karte gar nicht angeschlossen ist) gar keine Exception erzeugen. Bin mir bei diesen Proceduren auch noch nicht sicher, ob ich dann die Exceptions drin lassen sollte oder sie wieder rausnehme. Habe hier mal ein anderen Programmteil aus dem Projekt genommen und würde gern mal eure Meinung dazu hören, ob sinnvoll oder ob nicht sinnvoll oder vieleicht Verbesserungen möglich wären. Ich bitte dabei zu beachten, dass es sich dabei um meinen ersten Versuch handelt, mit Exceptions umzugehen und Fehlercodes in mein Programm einzubauen.
Delphi-Quellcode:
Ok ich denke, da ich fast alle Units ähnlich wie diese aufgebaut habe, ist die Vorgehensweise erkennbar. Die "Fehlermeldung(...)" ist dabei für mich eine Meldefunktion an eine Fehlerklasse, die anhand der Nummer den auftretenden Fehler zum Teil genau aber in einigen Fällen auch nur in einem gewissen Rahmen qualifiziert. In der Fehler-Klasse werden die übergebenen Nummern interpretiert und dann in eine Fehler-Log-Datei eingeschrieben. Bisher bin ich mit der Methode eigentlich zu frieden, da ich darüber mein Programm auch wenn bestimmte Geräte (wie z.B. die Controler-Board-Karte) nicht angeschlossen sind, starten kann und über den Status im Programm der Bediener mitbekommt, was genutzt werden kann und was er vieleicht doch nochmal einschalten muss oder was nicht funktioniert.
function TControlerBoard.DLLHandle_zuweisen: boolean;
begin //Protokoll.Protokolleingang('ControlerBoard', 'DLLHandle-Fkt'); Fehlermeldung(300); try ControlerDLL := TDLL_Datei.create('K8055D.DLL'); if ControlerDLL.Vorhanden then begin DLL_Handle := ControlerDLL.Handle; result := true; end else begin Fehlermeldung(301); DLL_Handle := 0; result := false; end except Fehlermeldung(302); result := false; end; //Protokoll.Protokollausgang('ControlerBoard', 'DLLHandle-Fkt'); end; function TControlerBoard.DLLFunktionen_laden: boolean; begin //Protokoll.Protokolleingang('ControlerBoard', 'DLL-Fkt laden'); try if DLL_Handle <> 0 then begin @OpenDevice := GetProcAddress(DLL_Handle, 'OpenDevice'); @CloseDevice := GetProcAddress(DLL_Handle, 'CloseDevice'); @ClearAllAnalog := GetProcAddress(DLL_Handle, 'ClearAllAnalog'); @ClearAllDigital := GetProcAddress(DLL_Handle, 'ClearAllDigital'); @ClearAnalogChannel := GetProcAddress(DLL_Handle, 'ClearAnalogChannel'); @ClearDigitalChannel := GetProcAddress(DLL_Handle, 'ClearDigitalChannel'); @OutputAnalogChannel := GetProcAddress(DLL_Handle, 'OutputAnalogChannel'); @SetDigitalChannel := GetProcAddress(DLL_Handle, 'SetDigitalChannel'); @ReadDigitalChannel := GetProcAddress(DLL_Handle, 'ReadDigitalChannel'); result := true; end else begin Fehlermeldung(303); result := false; end except Fehlermeldung(304); result := false; end; //Protokoll.Protokollausgang('ControlerBoard', 'DLL-Fkt laden'); end; function TControlerBoard.Initialising:boolean; begin try if (DLLHandle_zuweisen = true) and (DLLFunktionen_laden = true) then begin OpenDevice(0); ClearAllDigital; {Liste der einzuschaltenen Geräte per Funktion hier einfügen} V_Tische_Stromversorgung_einschalten; P_Tisch_Stromversorgung_einschalten; Spleissgeraet_einschalten; result := true; end else begin Fehlermeldung(305); result := false; end except Fehlermeldung(306); result := false; end; end; Über konstruktive Kritik würde ich mich sehr freuen. |
Re: Verständnisfrage zu try-except-finally
Keiner eine Meinung?
|
Re: Verständnisfrage zu try-except-finally
Exceptions kannst Du nur da abfangen, wo auch welche geworfen werden. GetProcAddress z.B. gehört nicht dazu, bei Misserfolg ist der Funktionszeiger dann eben nil. Außerdem bedeutet Exception Ausnahme, d.h. das sind Fehler, die nur unter besonders ungünstigen Bedingungen auftreten können (Abbruch der Netzwerkverbindung, nicht genügend Festplattenplatz, kein Datenträger im Laufwerk oder etwas in der Art) und auf die Du keinen Einfluss hast. Alle durch Dich vermeidbaren Fehlerquellen solltest Du schon programmatisch abfangen.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:03 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