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 2 von 4     12 34      
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);
 
smudo

 
Delphi XE2 Professional
 
#11
  Alt 24. Mai 2006, 13:24
Zitat von Terminator:
Frag mich nun folgendes:
1. In obigen Beispiel wird doch s1 auch IMMER freigegeben oder hab ich da nen Denkfehler?.
2. Was passiert eigentlich wenn s1 nicht freigegeben wird? Wird nur unnötig Speicher belegt bis das Programm endet?
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.

2.) Ja. Es wird unnötiger Speicher belegt. Und das u.U. über das Programmende hinaus

René
  Mit Zitat antworten Zitat
Benutzerbild von RavenIV
RavenIV

 
Delphi 2007 Enterprise
 
#12
  Alt 24. Mai 2006, 13:35
Zitat von Terminator:

Delphi-Quellcode:
TRY
    ...
    sl:=TStringList.create; // Resource belegen
    ...
EXCEPT
    on E:Exception do
    begin
        Loggen
    end;
END;
s1.Free
Frag mich nun folgendes:
1. In obigen Beispiel wird doch s1 auch IMMER freigegeben oder hab ich da nen Denkfehler?.
2. Was passiert eigentlich wenn s1 nicht freigegeben wird? Wird nur unnötig Speicher belegt bis das Programm endet?


cu
Terminator
zu 1.
nein sl wird nicht freigegeben, weil der Ablauf in den except-Teil springt und anschliessend die procedure verlassen wird.
zu 2.
du bekommst Speicherlöcher (memory leaks), weil der Speicher belegt bleibt und nicht neu zugewiesen werden kann. Ausserdem kannst Du unerwartete Nebeneffekte bekommen, wenn Du z.B. sl neu erzeugst. Also immer schauen, dass alle mit create angelegte Objekte auch wieder ein free erfahren.
Klaus E.
  Mit Zitat antworten Zitat
smudo

 
Delphi XE2 Professional
 
#13
  Alt 24. Mai 2006, 13:39
Erster !
  Mit Zitat antworten Zitat
Benutzerbild von RavenIV
RavenIV

 
Delphi 2007 Enterprise
 
#14
  Alt 24. Mai 2006, 13:43
Zitat von smudo:
Erster !
es kam kein roter Kasten
Klaus E.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#15
  Alt 24. Mai 2006, 13:54
@Terminator
du kannst try-finally/except auch verschachteln

entweder erst die excption behandeln und dann freigeben
Code:
try
{
    ...
}
except
{
    ...
}
finally
{
    ...
}
=
Delphi-Quellcode:
try
  try
    ...
  except
    ...
  end;
finally
  ...
end;
oder erst freigeben und dann die Exception
Code:
try
{
    ...
}
finally
{
    ...
}
except
{
    ...
}
=
Delphi-Quellcode:
try
  try
    ...
  finally
    ...
  end;
except
  ...
end;
Aber stimmt schon ... zusammen (als ein Try-Block) hab ich's mir auch schon gewünscht
  Mit Zitat antworten Zitat
MStoll

 
Turbo Delphi für Win32
 
#16
  Alt 24. Mai 2006, 13:55
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.
Hi,

wenn nur noch der Except-Block ausgeführt werden würde, das wäre ja schrecklich. Das ist nicht so! Es kann ja nicht sein, dass man bei ner Exception keine Möglichkeit mehr hat, hinter dem Teil mit der Exception weiterzumachen.

Gruß
Michael
  Mit Zitat antworten Zitat
Sidorion
 
#17
  Alt 24. Mai 2006, 16:58
Dass das noch niemandem aufgefallen ist:
Zitat:
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;
Hier wird Query1.Next nur gerufem, falls es zu einer Exception gekommen ist. Sobald ein Datensatz durchläuft, wirds ne Endlosschleife. besser:
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
    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;
    end;
  finally
    Query1.Next; // nächster Datensatz
  end;
end;
  Mit Zitat antworten Zitat
shmia

 
Delphi 5 Professional
 
#18
  Alt 24. Mai 2006, 17:05
@Sidorion: da hast du natürlich Recht, aber dein Lösungsvorschlag war nicht so gut.
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;
  end;
  Query1.Next; // nächster Datensatz
end;
Das Query1.Next ist nun an der richtigen Stelle; try..finally wird hier nicht benötigt.
Andreas
  Mit Zitat antworten Zitat
Sidorion
 
#19
  Alt 24. Mai 2006, 17:58
Schon, aber Du weißt ja, wie das ist: In fünf Monaten macht da irgendwer ein raise; dran und dann wars wieder keiner
  Mit Zitat antworten Zitat
altlastenverwalter
 
#20
  Alt 23. Aug 2010, 09:34
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!

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var a,b: double;
begin
 try
 b := 0;
 a := 666;
 a := 10 / b;
 except
   ShowMessage('nulldivision');
 end;
 ShowMessage(FloatToStr(a));
end;
Beide ShowMessage werden ausgeführt.

Ich weiß, dass dieser Thread alt ist, aber leider ist das der 3. Google-Treffer, wenn man nach Delphi-Exception sucht. Habe mich extra angemeldet in der Hoffnung, dass der Threadersteller seinen Eingangsbeitrag noch editieren könnte, damit nicht weiterhin diese Unwahrheit verbreitet wird.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 4     12 34      


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 08:31 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