AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials Delphi Falsche Verwendung von try...except...end

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

Ein Tutorial von shmia · begonnen am 20. Jul 2004 · letzter Beitrag vom 24. Feb 2011
Antwort Antwort
Seite 1 von 4  1 23     Letzte » 
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);
 
Robert Marquardt
 
#2
  Alt 20. Jul 2004, 19:08
2. ist nicht per se eine Suende.
Besonders in DLLs kann es unbedingt notwendig sein Exceptions zu unterdruecken.
Das Beispiel schert sich natuerlich nicht um eine genaue Aufschluesselung der Ursache, aber das muss ja nicht immer noetig sein.

(immer diese Shreipfeler)
  Mit Zitat antworten Zitat
shmia

 
Delphi 5 Professional
 
#3
  Alt 20. Jul 2004, 19:16
Zitat von Robert Marquardt:
2. ist nicht per se eine Suende.
Besonders in DLLs kann es unbedingt notwendig sein Exceptions zu unterdruecken.
Das Beispiel schert sich natuerlich nicht um eine genaue Aufschluesselung der Ursache, aber das muss ja nicht immer noetig sein.
Ja, da muss ich dir rechtgegeben.
Es gibt noch eine weitere Ausnahme:
Programmcode, der von Aussen über eine Automatisierungsschnittstelle aufgerufen wird, muss spezielle Vorkehrungen
treffen und darf auch ShowMessage zum Anzeigen benutzen, falls der Client die Exception nicht anzeigen kann.
Andreas
  Mit Zitat antworten Zitat
Rackergen2

 
Delphi 7 Enterprise
 
#4
  Alt 20. Jul 2004, 19:39
Zitat von shmia:
Delphi-Quellcode:
// 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;
Du hast da was falsch verstanden! Das Result:=false soll einer Funktion sagen, dass das Speichern nicht erfolgreich war und nicht die Ressource schützen!

Diese Verwendung sollte keinerlei Auswirkungen auf den Schutz haben, sondern vielmehr einen Funktionswert zurückgeben...

Wenn du dich schon beschweren willst, dann schreib wenigstens die ganze Funktion auf!

Delphi-Quellcode:
function TForm1.CreateAutorunFile(app, icon, destfile: String): boolean;
var
  sl: TStringList;
begin
  result:=true; //im Grunde erfolgreich
  sl:=TStringList.create; //TStringlist erstellen
  sl.add('[autorun]'); //Zeilen schreiben
  sl.add('OPEN='+app); //-"-
  sl.add('ICON='+icon); //-"-
  if copy(destfile, length(destfile)-4, 4)<>'.infthen destfile:=destfile+'.inf'; //im Zweifelsfall Endung anhängen

  try
    sl.SaveToFile(destfile); //Speicherversuch
  except
    result:=false; //Gescheitert? Dann false zurückgeben
  end;

  sl.free; //Ressource wieder freigeben
end;
Natürlich hätte man das Ganze durch try...finally schützen können, aber das hielt ich in dem Fall nicht für nötig! Und im Fall einer Wertezuweisung in einer Funktion ist das hier ebenso falsch, weil eine Sicherung NIE GEPLANT war...

Delphi-Quellcode:
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;
EDIT: Wir werden uns das mal merken und machen uns dann über dich lustig... Natürlich auch, wenn du mal vollkommen recht haben solltest! Aber diesmal:
  Mit Zitat antworten Zitat
Kernel32.DLL
 
#5
  Alt 20. Jul 2004, 19:46
es gibt da noch 'ne Sünde:

Man verwendet die try-except Konstruktion in einer Schleife. Bei einer Schleife, die sehr oft durchlaufen wird, verschlingt das Rechenzeit.
  Mit Zitat antworten Zitat
Terminator
 
#6
  Alt 24. Jul 2004, 10:52
Hi all,


bei Delphi is mir mit als erstes aufgefallen, dass man except und finally nicht miteinander verwenden kann.
In Java bsw. können folgende Blöcke gebildet werden:

Code:
try
{
    ...
}
except
{
    ...
}
finally
{
    ...
}

Da ich auf Exceptions reagieren möchte (log diese in ne Datei), setze ich finally so gut wie gar nicht ein.
Jetzt hab ich in dem Beispiel allerdings gelesen, dass mein Ansatz eigentlich falsch ist.

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
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry

 
Delphi 2006 Professional
 
#7
  Alt 24. Jul 2004, 11:01
ich finde das erste nicht als Todsünde - Es gibt programme die sind für Leute die 0 Ahnung haben. Wenn diese User bei einem Musikprogramm alle Dateien im Ordner markieren und dem programm hinzufügen wäre es unzumutbar 20 Fehlermeldungen zu bringen weil eventuell Textdateien & Cover mit auf das Programm gedroppt wurden. Oder wenn man beim Start des programmes alle dateien aus einem dump läd und eine wechseldatenträger nicht gefunden wird kann ich nicht bei 20 000 Dateien dem Nutzer jedesmal eine Meldung bringen das die Datei nicht gefunden wurde. Da ist es nutzerfreundlicher wenn die datei einfach nicht geadded wird
Jens
  Mit Zitat antworten Zitat
tommie-lie
 
#8
  Alt 24. Jul 2004, 12:03
Zitat von SirThornberry:
Es gibt programme die sind für Leute die 0 Ahnung haben. Wenn diese User bei einem Musikprogramm alle Dateien im Ordner markieren und dem programm hinzufügen wäre es unzumutbar 20 Fehlermeldungen zu bringen weil eventuell Textdateien & Cover mit auf das Programm gedroppt wurden.
Wenn der Anwender 0 Ahnung hat, muss der Entwickler Ahnung haben.
Hat der Entwickler 0 Ahnung, muss zwangsläufig der Anwender Ahnung haben.
In solchen Fällen versuche ich nicht einfach blind ein .jpg per Mediaplayer abzuspielen, sondern ich (als Entwickler) schaue vorher, was ich denn da für Dateien kriege (Notfalls anhand des Dateinamens). Dann gibt's keine Exceptions und ich kann selber entscheiden ob ich für jede Datei eine Meldung anzeige oder nur für die erste oder überhaupt nicht (letzteres wäre bei sowas wohl das sinnvollste).

Zitat:
Oder wenn man beim Start des programmes alle dateien aus einem dump läd und eine wechseldatenträger nicht gefunden wird kann ich nicht bei 20 000 Dateien dem Nutzer jedesmal eine Meldung bringen das die Datei nicht gefunden wurde.
Auch da ist es sinnvoller, wenn ich mich als Entwickler vorher darum kümmere, wohin ich meine Daten schreiben will, indem ich vorher schaue, ob mein Zieldatenträger existiert (genauso wie wenn ich Dateien überschreiben soll). Und 20000 Fehlermeldungen sollten bei sowas auhc nicht auftreten. Wenn ich eine Datei schon nicht schreiben kann, weil das Medium nicht vorhanden oder voll ist, werde ich wohl die 19999 weiteren in meiner Liste auch nicht schreiben können, ergo fordere ich den User auf, ein neues Medium zu mounten oder erstmal Platz auf dem bereits vorhandenen zu schaffen, und solange warte ich und versuche nicht ständig drauf zuzugreifen.

Die Liste der Sünden gilt für Entwickler mit Grips, für Anfänger sind das garantiert keine Sünden, ganz einfach weil die's nicht besser wissen und nicht die nötige Erfahrung haben.
  Mit Zitat antworten Zitat
Benutzerbild von phlux
phlux

 
Delphi 6 Personal
 
#9
  Alt 24. Jul 2004, 12:13
Ich fand des Tut ganz okay hat mir das Exceptionhandling etwas näher gebracht (Exceptions? Brauch ich net )
Christian "phlux" Arndt
  Mit Zitat antworten Zitat
torud

 
Delphi XE5 Professional
 
#10
  Alt 24. Mai 2006, 13:01
Ich fand das Tut auch ganz toll, denn ich bin auch so ein Schlumi, der gern mal was in einen solchen Block packt, aber nichts damit anfängt. Ich denke, das ich da demnächst mehr darauf achten werde und das war auch sicher einer der Denkansätze für das Einbringen eines solchen Threads.
  Mit Zitat antworten Zitat
Themen-Optionen Tutorial durchsuchen
Tutorial durchsuchen:

Erweiterte Suche
Ansicht

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 06:16 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