AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials Delphi Falsche Verwendung von try...except...end
Tutorial durchsuchen
Ansicht
Themen-Optionen

Falsche Verwendung von try...except...end

Ein Tutorial von shmia · begonnen am 20. Jul 2004 · letzter Beitrag vom 24. Feb 2011
Antwort Antwort
Seite 3 von 4     123 4      
shmia
Registriert seit: 2. Mär 2004
Viele Programmierer verwenden try...except...end auf eine falsche Weise.
Es gibt mindestens 5 "Sünden", die man begehen kann:

Delphi-Quellcode:
// 1. Sünde
// jede Exception wird komplett verschluckt
// Niemand wird je erfahren, warum das Programm nicht funktioniert !!!
// dass die Exception.Message in der Delphi IDE angezeigt wird zählt nicht,
// denn nach Murphy treten Fehler grundsätzlich beim Endbenutzer auf
try
   MachWas;
except
end;

// 2. Sünde
// Exceptions werden abgefangen und als Returncode umgesetzt
// niemand wird je erfahren, warum eine Funktion einen Fehlercode liefert
try
   MachWas;
except
   Result := 1; // oder auch Result := False;
end;

// 3. Sünde
// Exception wird abgefangen und mit ShowMessage eine Meldung präsentiert
// niemand wird je die wahre Ursache erfahren
// in einer Schleife können tausende Meldungen produziert werden
try
   MachWas;
except
   ShowMessage('es ist Fehler in MachWas aufgetreten');
// ShowMessage('Es ist ein Fehler aufgetreten !'; // geht's noch genauer ??
   Exit;
end;

// 3. Sünde B
// Manchmal führt die Meldung des Programmierers total in die falsche Richtung
try
   liste.LoadFromFile('C:\autoexec.bat');
   liste.Add(...)
   ....
   liste.SaveToFile('C:\autoexec.bat');
except
   // die Meldung kann völlig falsch sein.
   // eine Exception an dieser Stelle bedeutet nicht, dass die AUTOEXEC.BAT nicht vorhanden ist
   // dann lieber eine nichtssagende Fehlermeldung, als eine Falsche
   ShowMessage('C:\AUTOEXEC.BAT nicht gefunden !');
   Exit;
end;


// 4. Sünde
// Exception wird abgefangen und die Meldung mit ShowMessage präsentiert
// die orginale Exception-Class geht verloren (ein Exception-Objekt kann auch mehr Informationen
// tragen als nur eine Message (siehe EOleException); die Infos sind verloren)
// in einer Schleife können tausende Meldungen produziert werden
// es wird zwar jetzt die richtige Meldung angezeigt, aber wenn man mit Exit zurückkehrt
// hätte man das try...except gleich weglassen können
try
   MachWas;
except
   on E:Exception do
   begin
      ShowMessage(E.Message);
      Exit;
   end;
end;

// 5. Sünde
// try...except wird verwendet, um eine Resource (Speicher, Handles,...) zu schützen
// Resourcen werden mit einem Resourceschlutzblock (try...finally) geschützt und nicht
// mit einem falsch verstandenem try...except
// in folgendem Beispiel wird try..except falsch verwendet
  sl:=TStringList.create;
  sl.add('[autorun]');
  sl.add('OPEN='+app);
  sl.add('ICON='+icon);
  if copy(destfile, length(destfile)-4, 4)<>'.infthen destfile:=destfile+'.inf';

  try
    sl.SaveToFile(destfile);
  except
    result:=false;
  end;
  sl.free;
// Richtig wäre
  sl:=TStringList.create; // Resource belegen
  try // direkt danach folgt das try
    sl.add('[autorun]');
    sl.add('OPEN='+app);
    sl.add('ICON='+icon);
    if copy(destfile, length(destfile)-4, 4)<>'.infthen destfile:=destfile+'.inf';

    sl.SaveToFile(destfile);
  finally
    sl.Free; // die Resource wird immer freigegeben, egal was passiert
  end;
Wenn man obige Sünden nicht begeht, wird man belohnt:
man kann z.B. Exceptions, die bis an die Oberfläche kommen automatisch in einer Log-Datei speichern
oder man kann dem Benutzer zusätzlich einen Hilfe-Button (natürlich kontextsensitiv) anbieten.
Exceptions mit Help-Button anzeigen
Man könnte die Exception-Infos auch per Email zum Programmierer schicken lassen.
("Bug-Report" per EMail)

Richtige Verwendung von try...except...end
Delphi-Quellcode:
// in folgendem Beispiel werden Daten aus einer Query gelesen
// Fehler werdem in einem Memo protokolliert und der Lesevorgang geht weiter
// es werden keine Informationen unterdrückt, sondern die Fehlermeldungen werden protokolliert
while not Query1.Eof do
begin
  try
    MachWas(Query1);
  except
    on E:Exception do
    begin
       MemoLog.Lines.Add('Fehler in MachWas');
       MemoLog.Lines.Add(E.ClassName+':'+E.Message);
       MemoLog.Lines.Add('Record: ' +IntToStr(Query1.RecNo);
    end;
   Query1.Next; // nächster Datensatz
  end;
end;

// in folgendem Beispiel wird eine Exception abgefangen mit Informationen angereichert
// und erneut ausgelöst
try
   MachWas(x, y, color);
except
   on E:Exception do // Eception abfangen
   begin
      // mit *nützlichen Informationen* anreichern
      // die Meldung wird mehrzeilig durch #13#10
      E.Message := Format('Fehler in MachWas(%d, %d, %d)'#13#10, [x, y, color]) +
         E.Message;
      Raise; // Erneut auslösen !
   end;
end;

// Manchmal möchte man wirklich jede Exception unterdrücken
try
   anzahl := StrToInt(EditAnzahl.Text);
except
   anzahl := 1;
end;

// hier empfiehlt es sich die Exception zu vermeiden
   if EditAnzahl.Text = 'then
     anzahl := 1
   else
   begin
     anzahl := StrToInt(EditAnzahl.Text);
   end;
// Es gibt natürlich noch elegantere Lösungen (StrToIntDefault kann sich jeder selber bauen)
  anzahl := StrToIntDefault(EditAnzahl.Text, 1);
 
Benutzerbild von Bernhard Geyer
Bernhard Geyer

 
Delphi 10.4 Sydney
 
#21
  Alt 23. Aug 2010, 08:39
Die 5. Sünde ist Unfug (zumindest bei Delphi 6 - hab gerade keine andere Version parat).

Einen finally-Handler benötigt man nur, wenn man Exceptions nicht gesondert behandeln möchte.
Selbstverständlich wird nach dem Except normal weitergemacht und eben nicht die Prozedur verlassen!
Ist kein Unfug. Finally ist zur Freigabe von Ressourcen zu verwenden! Es wurde auch nicht davon gesprochen das im except-Teil die Funktion verlassen wird. Wird z.B. statt einer Exption ein exit aufgerufe wird dein Code nach dem Except nicht aufgerufen, der Finally-Teil trotzdem.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

 
Delphi 12 Athens
 
#22
  Alt 23. Aug 2010, 08:53
Und wenn in der Exception-Behandlung auch noch eine Problem auftritt, dann wird hier auch nichts mehr freigegen.

Dein ShowMessage kann auch aus verschiedenen Gründen zu einer Exception führen und dann war's das mit der Code-Ausführung danach.

(Ja, ich geb zu, daß ich diese Art der Freigabe auch an einigen Stellen einsetze, aber in diesen Fällen hatte das A) seine Gründe (vorallem um noch ein paar Millisekündchen einzusparen, bei der Masse an Ausführungen) oder einfach nur wegen des kürzeren Codes und vorallem B) wußte ich, daß es in dieser Exceptionbehandlung garantiert zu keinem Problem kommen konnte (es sei denn es gibt so masive Probleme, daß das Programm sowieso gleich komplett verreckt wird).

Aber in allen anderen Fällen kann ich ebenfalls nur die Freigabe über ein zusätzliches Try-Finally empfehlen.
Vorallem da es so auch offensichtlicher wird, daß hier immer freigegeben, bzw daß dieser Code immer ausgeführt wird.

Geändert von himitsu (23. Aug 2010 um 08:55 Uhr)
  Mit Zitat antworten Zitat
altlastenverwalter
 
#23
  Alt 23. Aug 2010, 09:30
Es wurde auch nicht davon gesprochen das im except-Teil die Funktion verlassen wird.
Doch. Smudo hat genau das behauptet:

Zitat von smudo;:
:
1.) Nein, wird nicht immer freigegeben. Nach einer Exception wird nur noch der Except-Block ausgeführt. Du musst also auch in den Except-Block das freigeben integrieren.
Wird z.B. statt einer Exption ein exit aufgerufe wird dein Code nach dem Except nicht aufgerufen, der Finally-Teil trotzdem.
Das stimmt. Exit wurde aber bisher nicht erwähnt.
Vor allem hat es nichts mehr mit Sünde 5 von shmia zu tun. Dort ERSETZT finally einfach das except und die eigentliche Fehlerbehandlung fehlt.
  Mit Zitat antworten Zitat
Benutzerbild von implementation
implementation

 
FreePascal / Lazarus
 
#24
  Alt 23. Aug 2010, 11:23
Der try-finally-Block ist ja auch nicht dazu da um Exceptions zu behandeln.
Falls im try-Block eine auftritt, bleibt sie geworfen und wird weiterhin Ebene für Ebene hochgereicht bis sie behandelt wird.
Delphi-Quellcode:
procedure Prozedur;
begin
  try
    TueWas;
  finally
    // Die Exception wird absichtlich nicht abgefangen.
    GebeResourcenFrei;
  end;
end;

...

try
  TueWas;
  Prozedur;
  TueWas;
except
  // Denn sie soll HIER behandelt werden.
  on E: EChuckNorrisIsDead do
  begin
    ...
  end;
end;
Wenn man statt dem oberen try-finally ein try-except verwendet, wird die Exception ja abgefangen.
Und das soll doch überhaupt nicht passieren.
Marvin
  Mit Zitat antworten Zitat
Kieni

 
Delphi 2 Desktop
 
#25
  Alt 9. Dez 2010, 14:33
Hallo,

ich habe mal eine Frage. Ist die Verwendung von try...except im folgenden Code richtig angewandt, bzw möglich:

Code:
  If WinVer.VersionText = 'Microsoft Windows XP' then
  begin
    S:='Install .NET Framework 3.5';
    WriteLog(S);
    try
      ExecuteCommand(installDir+'\dotNet3.5.exe',SW_SHOWNORMAL,true,nil,nil);
      S:='finished at ' + DateTimeToStr(Now);
      WriteLog(S);
    except
      on E:Exception do
      begin
        Writelog('Error while installing dotNet 3.5');
        Writelog(E.ClassName+':'+E.Message);
      end;
    end;
  end;
Gruß Kieni
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

 
Delphi 11 Alexandria
 
#26
  Alt 9. Dez 2010, 14:40
Das ist richtig so: wenn das ExecuteCommand fehlschlägt, dann wird der Fehler mitgeloggt.

[edit] Nachtrag: das setzt natürlich voraus, dass im Fehlerfall auch wirklich eine Exception geworfen wird [/edit]
Detlef

Geändert von DeddyH ( 9. Dez 2010 um 14:48 Uhr)
  Mit Zitat antworten Zitat
sgbSoftwareEntwickler

 
Delphi XE Professional
 
#27
  Alt 24. Feb 2011, 08:11
Vielen Dank für den Beitrag shmia
Thomas
  Mit Zitat antworten Zitat
MephistoMyRo

 
Delphi XE Enterprise
 
#28
  Alt 24. Feb 2011, 10:29
Ich will ja nicht kleinlich sein, aber:
Delphi-Quellcode:
// in folgendem Beispiel werden Daten aus einer Query gelesen
// Fehler werdem in einem Memo protokolliert und der Lesevorgang geht weiter
// es werden keine Informationen unterdrückt, sondern die Fehlermeldungen werden protokolliert
while not Query1.Eof do
begin
  try
    MachWas(Query1);
  except
    on E:Exception do
    begin
       MemoLog.Lines.Add('Fehler in MachWas');
       MemoLog.Lines.Add(E.ClassName+':'+E.Message);
       MemoLog.Lines.Add('Record: ' +IntToStr(Query1.RecNo);
    end;
   Query1.Next; // nächster Datensatz
  end;
end;
Wenn MachWas(Query1) keine Exception auslöst, dann wird das hier ne Endlos-Schleife...

Query1.Next; // nächster Datensatz müsste ein end weiter. Bitte korregieren oder ich hab da etwas falsch verstanden.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

 
Delphi 11 Alexandria
 
#29
  Alt 24. Feb 2011, 10:34
Wie kommst Du darauf?
Detlef
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

 
Delphi 10.2 Tokyo Professional
 
#30
  Alt 24. Feb 2011, 10:35
Wie kommst Du darauf?
Weil das Query1.Next im except-Block steht.
Michael
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 4     123 4      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:33 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