Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   FreePascal Try Except Problem (https://www.delphipraxis.net/183732-try-except-problem.html)

AlexII 31. Jan 2015 13:48

Try Except Problem
 
Hallo,

ich habe folgendes Problem. Ich lade eine Datei in mein Programm, falls das schief gehen soll, soll der alte Pfad wieder gesetzt werden. Das klappt aber irgendwie nicht, wieso eigentlich?


Delphi-Quellcode:
procedure TForm1.OpenDialog1BitBtnClick(Sender: TObject);
var
  str: String = '';
begin
  str := Edit1.Caption;

  try
    if OpenDialog1.Execute then
    begin
      Edit1.Caption := OpenDialog1.FileName;
    end;
  except
    on E: Exception do MessageDlg('Fehler: Die Datei konnte nicht geladen werden!'
    + sLineBreak + sLineBreak + E.ClassName + sLineBreak + E.Message, mtError, [mbOk], 0);

    Edit1.Caption := str; // Hier der Fehler: Syntax error, "ON" expected but "identifier EDIT1" found
  end;
end;

Danke!

DeddyH 31. Jan 2015 13:52

AW: Try Except Problem
 
begin und end kennst Du?

AlexII 31. Jan 2015 14:09

AW: Try Except Problem
 
Zitat:

Zitat von DeddyH (Beitrag 1288412)
begin und end kennst Du?

Ja, aber es hilft trotzdem nicht.

Delphi-Quellcode:
procedure TForm1.OpenDialog1BitBtnClick(Sender: TObject);
var
  str: String = '';
begin
  str := Edit1.Caption;

  try
    if OpenDialog1.Execute then
    begin
      Edit1.Caption := OpenDialog1.FileName;
    end;
  except
    on E: Exception do
    begin
      MessageDlg('Fehler: Die Datei konnte nicht geladen werden!'
      + sLineBreak + sLineBreak + E.ClassName + sLineBreak + E.Message, mtError, [mbOk], 0);
    end;

    Edit1.Caption := str; // Hier der Fehler: Syntax error, "ON" expected but "identifier EDIT1" found
  end;
end;

Plastewolf 31. Jan 2015 14:17

AW: Try Except Problem
 
Delphi-Quellcode:
procedure TForm1.OpenDialog1BitBtnClick(Sender: TObject);
var
  str: String = '';
begin
  str := Edit1.Caption;

  try
    if OpenDialog1.Execute then
    begin
      Edit1.Caption := OpenDialog1.FileName;
    end;
  except
    on E: Exception do
    begin
      MessageDlg('Fehler: Die Datei konnte nicht geladen werden!'
      + sLineBreak + sLineBreak + E.ClassName + sLineBreak + E.Message, mtError, [mbOk], 0);

      Edit1.Caption := str; // Hier der Fehler: Syntax error, "ON" expected but "identifier EDIT1" found
    end;
  end;
end;
Gruß

AlexII 31. Jan 2015 14:24

AW: Try Except Problem
 
Ah jah... alles klar! Danke!

Sir Rufo 31. Jan 2015 15:24

AW: Try Except Problem
 
Man kann es sich schwer oder eben einfach machen:
Delphi-Quellcode:
procedure TForm1.OpenDialog1BitBtnClick(Sender: TObject);
begin
    if OpenDialog1.Execute then
    begin
      LoadFile ( OpenDialog1.Filename );
      Edit1.Caption := OpenDialog1.FileName;
    end;
end;

himitsu 31. Jan 2015 15:53

AW: Try Except Problem
 
In dem Code gibt es eigentlich nichts zum Knallen und wenn es doch knallt, dann ist eh alles zu spät und dann hilft auch keine Exception-Behandlung mehr.

Und wenn ich mir den ersten Code so anseh:
  • Wo wird da eine Datei ausgelesen?
    Nichts da, also kann es dadurch auch nicht knallen und die Fehlermeldung ist somit total falsch und verwirrend.
  • Was sollte das mit der Variable und Caption?
    Die wird ausgelesen und genau so wieder zugesiwsen, also keinerlei Ändeurng und somit sinnlos.
  • Und das mit dem Begin+End ...
    Ich hätte gedacht das hättest du langsam mal gelernt.

Ergebnis siehe
Zitat:

Kaum macht man's richtig - schon funktioniert's :mrgreen:

jaenicke 1. Feb 2015 08:21

AW: Try Except Problem
 
Wenn das Laden fehlschlägt, sollte der Pfad sicherlich auch nicht angezeigt werden:
Delphi-Quellcode:
procedure TForm1.OpenDialog1BitBtnClick(Sender: TObject);
begin
  {$BOOLEVAL OFF}
  if OpenDialog1.Execute and LoadFile(OpenDialog1.Filename) then
    Edit1.Caption := OpenDialog1.FileName;
end;

Bernhard Geyer 1. Feb 2015 08:27

AW: Try Except Problem
 
Zitat:

Zitat von jaenicke (Beitrag 1288436)
Wenn das Laden fehlschlägt, sollte der Pfad sicherlich auch nicht angezeigt werden:
Delphi-Quellcode:
procedure TForm1.OpenDialog1BitBtnClick(Sender: TObject);
begin
  {$BOOLEVAL OFF}
  if OpenDialog1.Execute and LoadFile(OpenDialog1.Filename) then
    Edit1.Caption := OpenDialog1.FileName;
end;

Mit Booleval wird aber auf jedenfall die LoadFile-Methode ausgeführt auch wenn diese über einen alten Wert in OpenDialog1.Filename aufgerufen würde (z.B. Letzte Verwendung). Ich bin mir nicht sicher ob im abgebrochenen Zustand der String leer ist.

Sir Rufo 1. Feb 2015 09:45

AW: Try Except Problem
 
Wie geht man mit Exceptions um?

Wenn man die behandeln kann, dann und nur dann nimmt man einen
Delphi-Quellcode:
try except
. Ansonsten macht man sich das Verhalten einer Exception zunutze (alle Anweisungen danach werden nicht mehr ausgeführt):
Delphi-Quellcode:
procedure TForm1.LoadFileButtonClick( Sender : TObject );
begin
  if OpenDialog1.Execute then
  begin
    Memo1.LoadFromFile( OpenDialog1.Filename );
    Edit1.Text := OpenDialog1.Filename;
  end;
end;
Wenn jetzt
Delphi-Quellcode:
Memo1.LoadFromFile( OpenDialog1.Filename );
eine Exception auslöst, dann wird
Delphi-Quellcode:
Edit1
nicht verändert und es erscheint der Dialog mit der Fehlermeldung.

Ist es das Verhalten, was gesucht wird?

Und komisch, das bekommt man ohne diese seltsame Schnickschnack Programmierung. Und irgendwie ist es auch noch einfacher.

Das Herumfuhrwerken an Exceptions und das Erstellen von Wrapper-Methoden, die im Fall der Fälle dann statt einer Exception einen bestimmten Rückgabewert liefern, führt meistens nur zu wesentlich mehr und unlesbarem Code und in 99% aller Fälle dazu, dass Programmierfehler unentdeckt bleiben.

Exceptions sind nicht der Feind, aber das Abfangen ohne wirkliche Behandlung ist der erste Schritt um die Anwendung zu meinem Feind zu machen.

Ja ich höre schon wieder die Stimmen "aaaaaber, ...". Natürlich kann man Exceptions abfangen, aber eben nur wenn man diese auch behandeln kann. Ohne sinnvolle Behandlung ist nur noch ein erneutes Werfen sinnvoll, wobei hier auch eine Übersetzung bzw. Umleitung auf eine eigene Exceptionklasse erfolgen kann.
Delphi-Quellcode:
MyConnection.StartTransaction;
try
  MyQueryA.ExecSQL;
  MyQueryB.ExecSQL;
  MyConnection.Commit;
except
  MyConnection.Rollback;
  raise;
end;

p80286 1. Feb 2015 10:08

AW: Try Except Problem
 
Zitat:

Zitat von Sir Rufo (Beitrag 1288440)
Wie geht man mit Exceptions um?

Wenn man die behandeln kann, dann und nur dann nimmt man einen
Delphi-Quellcode:
try except
. Ansonsten macht man sich das Verhalten einer Exception zunutze (alle Anweisungen danach werden nicht mehr ausgeführt)

Danke, daß Du das mal so klar ausgeführt hast. Meist finde ich nur Beschreibungen wie man mit Exceptions umgeht, aber nicht warum. Das muß sich der geneigte Benutzer oftmals selbst erarbeiten, und die Überprüfung der eigenen Erkenntnisse scheitert an wolkigen Aussagen, die mehr verschleiern als erklären.

Gruß
K-H

Sir Rufo 1. Feb 2015 10:57

AW: Try Except Problem
 
Der falsche Umgang mit Exceptions (ich bezeichne das gerne als eine lethale Exception-Phobie) führt zu den interessantesten Problemen, die nur durch aufwändigstes Debugging zu beheben sind:
Delphi-Quellcode:
function TForm1.LoadFromFile( const AFilename : string ) : Boolean;
begin
  try
    Memo1.LoadFromFile( AFilename );
    Result := True;
  except
    Result := False;
  end;
end;
Sieht doch schick aus und wir werden niemals eine Exception sehen - GottSeiDank!
Delphi-Quellcode:
procedure TForm1.LoadFileButtonClick(Sender : TObject );
begin
  if OpenDialog1.Execute then
  begin
    if LoadFromFile( OpenDialog1.Filename ) then
      Edit1.Text := OpenDialog1.Filename
    else
      ShowMessage( 'Datei nicht gefunden ' + OpenDialog1.Filename );
  end;
end;
Ei, was haben wir uns da eine schöne robuste KeineExceptionWerfende Funktionalität gebaut (stundenlang-auf-die-schultergeklopfe).

Irgendeine Knalltüte (in 99% der Fälle, ist man das sogar selber) hat uns aber irgendwo in den Code folgende Zeile eingebaut:
Delphi-Quellcode:
procedure TForm1.SomethingSpecial;
begin
  // mehrere Zeilen Code
  Memo1 := nil;
  // noch mehr Zeilen Code
end;
Jetzt wird keine Datei mehr geladen selbst wenn es die Datei gibt und die Anwendung behauptet in der Meldung steif und fest, dass es diese Datei nicht gibt. Ich wünsche eine fröhliche Fehlersuche, wenn der Anwender mitteilt, dass keine Datei mehr geladen wird. Natürlich behaupten wir - wegen unsere unfehlbaren Methode - dass es diese Datei dann eben auch nicht gibt. Und wir testen das Laden bis zum Erbrechen und werden keinen Fehler finden und natürlich den Anweder einfach als DAU abstempeln.

Woher sollen wir denn wissen, dass dieses Verhalten nur dann auftaucht, wenn man vorher diese oder jene Funktion ausgeführt hat, die eben dieses
Delphi-Quellcode:
Memo1 := nil;
ausführt?

Ja, woher soll man das wissen?

Und was ist damit?
Delphi-Quellcode:
procedure TForm1.LoadFromFile( const AFilename : string );
begin
  Memo1.LoadFromFile( AFilename );
end;

procedure TForm1.LoadFileButtonClick(Sender : TObject );
begin
  if OpenDialog1.Execute then
  begin
    LoadFromFile( OpenDialog1.Filename );
    Edit1.Text := OpenDialog1.Filename;
  end;
end;
Keine Datei gefunden -> Fehlerdialog mit EFileNotFound erscheint, Edit1 bleibt unverändert
Memo1 ist nil -> Fehlerdialog mit EAccessViolation erscheint, Edit1 bleibt unverändert

Suchst du noch oder hast du den Fehler schon behoben ...
bzw.
Diskutierst du noch mit dem Anwender oder suchst du schon den Fehler ...

himitsu 1. Feb 2015 11:13

AW: Try Except Problem
 
Zitat:

Zitat von Sir Rufo (Beitrag 1288445)
Der falsche Umgang mit Exceptions (ich bezeichne das gerne als eine lethale Exception-Phobie) führt zu den interessantesten Problemen, die nur durch aufwändigstes Debugging zu beheben sind:
Delphi-Quellcode:
function TForm1.LoadFromFile( const AFilename : string ) : Boolean;
begin
  try
    Memo1.LoadFromFile( AFilename );
    Result := True;
  except
    Result := False;
  end;
end;
Sieht doch schick aus und wir werden niemals eine Exception sehen - GottSeiDank!

Noch "besser" ist nur :wall:
Delphi-Quellcode:
procedure TForm1.LoadFromFile( const AFilename : string );
begin
  try
    Memo1.LoadFromFile( AFilename );
  except
  end;
end;
und noch beliebter ist Code ala
Delphi-Quellcode:
try
  i := StrToInt('abc');
except
  i := 0;
end;

Sir Rufo 1. Feb 2015 11:16

AW: Try Except Problem
 
@himitsu

Bei so einem Code sollte einem eigentlich augenblicklich die Gicht in die Finger fahren. Mal sehen ob sich das mit einer IDE-Erweiterung realisieren lässt :mrgreen:

jaenicke 1. Feb 2015 16:26

AW: Try Except Problem
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1288437)
Mit Booleval wird aber auf jedenfall die LoadFile-Methode ausgeführt

Nein, denn ich habe die vollständige Auswertung ja aus- und nicht angeschaltet. ;-)

himitsu 1. Feb 2015 16:39

AW: Try Except Problem
 
Das sollte sowieso standardmäßig aus sein und auch besser aus bleiben.

jaenicke 1. Feb 2015 18:24

AW: Try Except Problem
 
Naja, eher sollte diese Einstellung vor Code, die sich auf die eine oder andere Richtung darauf verlässt, grundsätzlich gesetzt werden. ;-)

Dejan Vu 1. Feb 2015 22:15

AW: Try Except Problem
 
Ich würde mich bei Delphi gar nicht darauf verlassen. Sonst kommt irgendein Waldschrat mal auf die Idee, das anzuschalten und dann wundert man sich doch etwas.

Ich habe mich bei Delphi jedenfalls nie darauf verlassen.

himitsu 1. Feb 2015 22:37

AW: Try Except Problem
 
Ich hab es aufgegeben alle "Standards" selber nochmal zu setzen.

Wenn irgendein Idiot daran rumspielt, dann hat er Pech und muß mit den Konsequenzen leben.
Ich bin auch dafür, daß solche Optionen endlich mal aus den Projektoptionen raus fliegen oder es zumindestens mit mindestens 200 "Willst du das wirklich?"-Dialogen bestätigen muß.

Bernhard Geyer 1. Feb 2015 22:53

AW: Try Except Problem
 
Zitat:

Zitat von himitsu (Beitrag 1288510)
Ich hab es aufgegeben alle "Standards" selber nochmal zu setzen.

Wir bringen bei unseren Projekten einfach einen Compilerfehler wenn die (uralten) Compilerschalter falsch gesetzt sind.

himitsu 1. Feb 2015 23:19

AW: Try Except Problem
 
Jupp, das hab ich bei einigen Codes auch schon gemacht.

Leider gibt es IfOpt nur für die alten einbuchstabigen "+/-"-Optionen. :cry:


Einfach so umschalten und danach "zurückschalten" ist einfach nur falsch, vorallem wenn man sich vorher nicht den aktuellen Zustand merkt und danach "wirklich" wiederherstellt.
Leider fehlt auch noch eine Push/Pop-, bzw. Save/Restore-Möglichkeit, für die Compilerschalter.

Sowas wäre ja toll,
Delphi-Quellcode:
{$PUSH Options}  // oder {$PUSH Option X}
{$X+}
machwas;
{$POP Options}
bzw.
Delphi-Quellcode:
{$SAVEOPT X}
{$X+}
machwas;
{$RESTOREOPT X}
aber die Realität sähe etwa so aus :wall:
Delphi-Quellcode:
{$IFOPT X+} {$DEFINE _SaveX} {$ELSE} {$UNDEF _SaveX} {$ENDIF}
{$X+}
machwas;
{$IFNDEF _SaveX} {$X-} {$ENDIF}
denn
Delphi-Quellcode:
{$X+}
machwas;
{$X-}
wäre halt sowas von total falsch, wenn das X vorher schon aktiviert war und es danach nicht mehr ist. :warn:

BUG 2. Feb 2015 01:19

AW: Try Except Problem
 
Zitat:

Zitat von himitsu (Beitrag 1288517)
aber die Realität sähe etwa so aus :wall:
[DELPHI]{$IFOPT X+} {$DEFINE _SaveX} {$ELSE} {$UNDEF _SaveX} {$ENDIF}

Oder eben:
Delphi-Quellcode:
{$I StoreOptions}
{$X+}
// Zeug
{$I LoadOptions}
Die Includes müsste man nur einmal schreiben :mrgreen:
Aber stimmt schon, ein richtiger eingebauter Optionsstack wäre natürlich besser.

jaenicke 2. Feb 2015 04:45

AW: Try Except Problem
 
Zitat:

Zitat von himitsu (Beitrag 1288510)
Wenn irgendein Idiot daran rumspielt, dann hat er Pech und muß mit den Konsequenzen leben.
Ich bin auch dafür, daß solche Optionen endlich mal aus den Projektoptionen raus fliegen oder es zumindestens mit mindestens 200 "Willst du das wirklich?"-Dialogen bestätigen muß.

Ich habe mittlerweile einige Projekte gesehen, bei denen das absichtlich als Standard gesetzt war.
Aber welche anderen Einstellungen bringen denn die Logik potentiell so durcheinander, dass es tragisch wäre, wenn die anders gesetzt sind als erwartet? Da fallen mir ehrlich gesagt auf Anhieb keine ein.

JamesTKirk 2. Feb 2015 06:33

AW: Try Except Problem
 
Zitat:

Zitat von himitsu (Beitrag 1288517)
Einfach so umschalten und danach "zurückschalten" ist einfach nur falsch, vorallem wenn man sich vorher nicht den aktuellen Zustand merkt und danach "wirklich" wiederherstellt.
Leider fehlt auch noch eine Push/Pop-, bzw. Save/Restore-Möglichkeit, für die Compilerschalter.

Dann ist ja gut, dass bei diesem Thread Free Pascal drüber steht. Da geht das nämlich:
Delphi-Quellcode:
{$PUSH}
{$X+}
machwas;
{$POP}
:mrgreen:

Gruß,
Sven

Dejan Vu 2. Feb 2015 06:44

AW: Try Except Problem
 
Zitat:

Zitat von jaenicke (Beitrag 1288521)
Aber welche anderen Einstellungen bringen denn die Logik potentiell so durcheinander, dass es tragisch wäre, wenn die anders gesetzt sind als erwartet? Da fallen mir ehrlich gesagt auf Anhieb keine ein.

Wenn Du vollständige Bool'sche Evaluation meinst:
Delphi-Quellcode:
if CalculateFunctionWithSideEffec1 or CalculateFunctionWithSideEffec2 then
Klar, wer ist so dämlich... aber es ging ja nur ums einfallen.

jaenicke 2. Feb 2015 07:58

AW: Try Except Problem
 
Zitat:

Zitat von Dejan Vu (Beitrag 1288525)
Wenn Du vollständige Bool'sche Evaluation meinst:

Nein, ich meinte andere Einstellungen als eben die vollständige boolsche Auswertung. Klar, wenn man z.B. RTTI Informationen ausklammert, gibt es auch potentiell Fehler, aber das ändert erst einmal nichts an der Programmlogik.

p80286 2. Feb 2015 11:11

AW: Try Except Problem
 
Zitat:

Zitat von himitsu (Beitrag 1288447)
Delphi-Quellcode:
try
  i := StrToInt('abc');
except
  i := 0;
end;

@nicht nur Himitsu
Wenn die 0 als Fehler definiert ist und alle Datensätze gelesenwerden müssen, egal ob gültig oder nicht, und die Anwendung nicht dialoglastig ist, dann ist so ein Konstrukt nicht ganz falsch.

Gruß
K-H

himitsu 2. Feb 2015 11:14

AW: Try Except Problem
 
Doch, ist es.

Versuch mal soeinen Code zu debuggen :freak: und außerdem sind Exceptions eher für Ausnahmen und nicht zur "normalen" Programmsteuerung gedacht.
Delphi-Referenz durchsuchenVal, Delphi-Referenz durchsuchenTryStrToInt, Delphi-Referenz durchsuchenStrToIntDef usw.

Sir Rufo 2. Feb 2015 14:26

AW: Try Except Problem
 
Zitat:

Zitat von p80286 (Beitrag 1288559)
Zitat:

Zitat von himitsu (Beitrag 1288447)
Delphi-Quellcode:
try
  i := StrToInt('abc');
except
  i := 0;
end;

@nicht nur Himitsu
Wenn die 0 als Fehler definiert ist und alle Datensätze gelesenwerden müssen, egal ob gültig oder nicht, und die Anwendung nicht dialoglastig ist, dann ist so ein Konstrukt nicht ganz falsch.

Gruß
K-H

Ja wenn die Welt so einfach wäre ... und niemand diese Funktion anders definieren könnte, dann ja, aber dem ist nicht so, da diese Funktion eben doch auf einmal aus einer anderen Unit kommt, dort fehlerhaft ist und eigentlich eine Exception wirft und ich diese Information nie bekomme, weil ich toll alle Exceptions wegfange.

Niemals eine Exception blind wegfangen, sondern eher an so vielen Stellen wie möglich sogar eine Exception werfen, wenn die übergebenen Informationen so nicht verarbeitbar sind. Nur so kann ich eine zuverlässige und robuste Anwendung erstellen mit möglichst wenigen Bugs.

mm1256 2. Feb 2015 15:59

AW: Try Except Problem
 
Zitat:

Zitat von Sir Rufo (Beitrag 1288608)
Niemals eine Exception blind wegfangen, sondern eher an so vielen Stellen wie möglich sogar eine Exception werfen, wenn die übergebenen Informationen so nicht verarbeitbar sind. Nur so kann ich eine zuverlässige und robuste Anwendung erstellen mit möglichst wenigen Bugs.

Wahre Worte und mir aus der Seele gesprochen :thumb:

Dejan Vu 2. Feb 2015 20:39

AW: Try Except Problem
 
Und wenn man dann noch in Abstraktionsebenen denkt und Exceptions der aufgerufenen niedrigeren Abstraktionsebene abfängt, interpretiert und (abstrakter) weiterleitet, hat man einen Securitymanagement um sein Subsystem gelegt, mit dem sich schon recht komplexe und leicht zu wartende große Systeme implementieren lassen.

Mit Subsystem ist hier ist die Menge von Klassen in enger Kopplung gemeint, die sich gemeinsam um die Lösung eines Problemkomplexes kümmern.

Ein Beispiel ist der Communication-Layer, der die konkreten TCP- RDBMS- oder Streamexceptions abfängt, interpretiert (u.U. sogar repariert) und ggf. als 'CommunicationException' weiterleitet. Den Aufrufer interessiert es nämlich nicht, ob das gerade ein TCP-Timeout oder ein RDBMS-Lesefehler infolge explodierter Platten ist: Die Kommunikation funktioniert nicht, und das reicht ihm.

Sir Rufo 2. Feb 2015 20:45

AW: Try Except Problem
 
@Dejan Vu

Du solltest den einen Satz so darstellen
Zitat:

Zitat von Dejan Vu (Beitrag 1288659)
Ein Beispiel ist der Communication-Layer, der die konkreten TCP- RDBMS- oder Streamexceptions abfängt, interpretiert (u.U. sogar repariert) und ggf. als 'CommunicationException' weiterleitet.

Eventuell sogar noch farblich hervorheben ;)

Dejan Vu 2. Feb 2015 20:57

AW: Try Except Problem
 
Das hast Du ja jetzt gemacht. Doppelt hält besser. :mrgreen:


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:47 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz