Einzelnen Beitrag anzeigen

shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 

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

  Alt 20. Jul 2004, 18:15
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);
Andreas
  Mit Zitat antworten Zitat