AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Dokumentation und Exceptions - Wann muss ich was erwarten?
Thema durchsuchen
Ansicht
Themen-Optionen

Dokumentation und Exceptions - Wann muss ich was erwarten?

Offene Frage von "sahimba"
Ein Thema von Der schöne Günther · begonnen am 6. Jun 2013 · letzter Beitrag vom 6. Jun 2013
Antwort Antwort
Seite 1 von 2  1 2      
Der schöne Günther

Registriert seit: 6. Mär 2013
6.114 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 09:52
Delphi-Version: XE2
Das ist schon das (mindestens) dritte Thema zum Bereich Exceptions, ich werde irgendwie immer noch nicht warm damit, wie Exceptions in der Delphi-Welt generell gehandhabt werden.

Dass auf meine generelle Frage http://www.delphipraxis.net/173885-w...exception.html keine eindeutige Antwort existiert ist natürlich verständlich. Mein jetziges Anliegen ist stark verwandt mit meiner unbeantworteten Frage http://www.delphipraxis.net/174454-u...ns-finden.html :

Ich schaue mir fröhlich von Embarcadero Tutorial: Herstellen einer Verbindung zu einer SQLite-Datenbank (Delphi) an.

Dort finde ich:
Delphi-Quellcode:
try
   // Establish the connection.
   SQLConnection1.Connected := true;
   executeButton.Enabled := true;
   outputMemo.Text := 'Connection established!';
except
   on E: EDatabaseError do
      ShowMessage('Exception raised with message' + E.Message);
end;
Abgesehen davon, dass ich nicht einsehe, warum man die beiden Oberflächen-bezogenen Anweisungen nicht nach dem try-Block ausführen sollte: Woher kann ich wissen, dass ich einen EDatabaseError zu erwarten habe?

Die Dokumentation erzählt weder bei TSQLConnection::Connected noch TCustomConnection::Connected von einer möglichen Exception. Immerhin spricht sie von einer intern aufgerufenen Methode TCustomConnection.DoConnect. Doch auch hier: Kein Sterbenswort.

Und auf Dauer habe ich ehrlich gesagt auch nicht die Zeit, in Methoden wie TSQLConnection.DoConnect zu suchen, was denn hier alles Exceptions nach oben werfen könnte:

Delphi-Quellcode:
procedure TSQLConnection.DoConnect;
var
  ConnectionProps: TDBXProperties;
  Ind: Integer;
  ConnectionFactory: TDBXConnectionFactory;
  LoginParams: TStrings;
  SchemaOverride: string;
  SchemaOverrideList: TStringList;
  Password: string;
  MemoryConnectionFactory: TDBXMemoryConnectionFactory;
begin
  ConnectionProps := nil;
  LoginParams := TStringList.Create;
  MemoryConnectionFactory := nil;
  try
    if LoadParamsOnConnect then
    begin
      ConnectionFactory := TDBXConnectionFactory.GetConnectionFactory;
      TDBXConnectionFactory.Lock;
      try
        ConnectionProps := ConnectionFactory.GetConnectionProperties(ConnectionName);
        ConnectionProps := ConnectionProps.Clone;
      finally
        TDBXConnectionFactory.Unlock;
      end;
    end else
    begin
      ConnectionProps := TDBXProperties.Create;
      try
        ConnectionFactory := TDBXConnectionFactory.GetConnectionFactory;
      except
        MemoryConnectionFactory := TDBXMemoryConnectionFactory.Create;
        ConnectionFactory := MemoryConnectionFactory;
        ConnectionFactory.Open;
      end;
      ConnectionProps.AddProperties(FParams);
      if ConnectionProps.Properties.IndexOfName(TDBXPropertyNames.DriverName) = -1 then
        ConnectionProps.Add(TDBXPropertyNames.DriverName, DriverName);
    end;
    CheckLoginParams;
    ConnectionState := csStateConnecting;

    GetLoginParams(LoginParams);
    if LoginParams.Values[TDBXPropertyNames.Database] <> ConnectionProps[TDBXPropertyNames.Database] then
    begin
      ConnectionProps[TDBXPropertyNames.Database] := LoginParams.Values[TDBXPropertyNames.Database];
    end;

    SetCursor(HourGlassCursor);

    ConnectionProps.Add('UNLICENSED_DRIVERS', IntToStr(GDAL)); // Do not translate.

    FLoginUsername := LoginParams.Values[TDBXPropertyNames.UserName];
    if FLoginUserName <> 'then
      ConnectionProps[TDBXPropertyNames.UserName] := FLoginUsername;
    Password := LoginParams.Values[TDBXPropertyNames.Password];
    if Password <> 'then
      ConnectionProps[TDBXPropertyNames.Password] := Password;
    ConnectionProps.SetComponentOwner(self);
    ConnectionProps.Events.Events[sValidatePeerCertificate] := TEventPointer(ValidatePeerCertificate);

    ConnectionFactory.Lock;
    try
      FDBXConnection := ConnectionFactory.GetConnection(ConnectionProps);
    finally
      ConnectionFactory.Unlock;
    end;

    for Ind := 0 to FMonitorUsers.Count -1 do
      FMonitorUsers[Ind].UpdateTraceCallBack;

    SetCursor(HourGlassCursor);

    RegisterTraceCallback(True);

    FDefaultSchema := '';

    if (FDBXConnection.ProductName = 'BlackfishSQL') then {Do not localize}
    begin
      FDefaultSchema := 'DEFAULT_SCHEMA'; { Do not localize }
    end;

    SchemaOverride := ConnectionProps[TDBXPropertyNames.SchemaOverride];

    if (SchemaOverride = '') and LoadParamsOnConnect then
    begin
      TDBXConnectionFactory.Lock;
      try
        SchemaOverride := ConnectionFactory.GetDriverProperties(ConnectionProps[TDBXPropertyNames.DriverName])
                          [TDBXPropertyNames.SchemaOverride];
      finally
        TDBXConnectionFactory.Unlock;
      end;
    end;

    if SchemaOverride <> 'then
    begin
      SchemaOverrideList := TStringList.Create;
      try
        SchemaOverrideList.Delimiter := '.';
        SchemaOverrideList.DelimitedText := SchemaOverride;
        if SchemaOverrideList.Count = 2 then
        begin
          if (SchemaOverrideList[0] = '%') or (SchemaOverrideList[0] = FLoginUsername) then
            FDefaultSchema := SchemaOverrideList[1];
        end;
      finally
        SchemaOverrideList.Free;
      end;
    end;

    ConnectionOptions;

    ConnectionState := csStateOpen;
  finally
    FreeAndNil(MemoryConnectionFactory); // If allocated, free it.
    SetCursor(DefaultCursor);
    LoginParams.Free;
    ConnectionProps.Free;
    if ConnectionState = csStateConnecting then // an exception occurred
    begin
      ConnectionState := csStateClosed;
      if Assigned(FDBXConnection) then
        FreeAndNil(FDBXConnection)
    end;
  end;
end;

Deshalb: Irgendwoher muss die Doku ja die Weisheit nehmen, dass irgendwoher ein EDatabaseError kommen kann. Ich bin zu dumm, das zu sehen. Bitte helft mir.
  Mit Zitat antworten Zitat
Lemmy

Registriert seit: 8. Jun 2002
Ort: Berglen
2.366 Beiträge
 
Delphi 10.3 Rio
 
#2

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 11:14
Abgesehen davon, dass ich nicht einsehe, warum man die beiden Oberflächen-bezogenen Anweisungen nicht nach dem try-Block ausführen sollte: Woher kann ich wissen, dass ich einen EDatabaseError zu erwarten habe?
....
Deshalb: Irgendwoher muss die Doku ja die Weisheit nehmen, dass irgendwoher ein EDatabaseError kommen kann. Ich bin zu dumm, das zu sehen. Bitte helft mir.

ist doch ganz einfach: Du weißt das aus der Dokumentation - in diesem Fall aus dem entsprechenden Codebeispiel.

Der Doku-Schreiber weiß, dass da ein EDatabaseError aufschlagen kann (so lange er keinen Fehler gemacht hat) vom Entwickler, der die betreffende Bibliothek geschrieben hat, und der sollte das eigentlich wissen.

was denn hier alles Exceptions nach oben werfen könnte:
das ist eigentlich Aufgabe der Dokumentation, das zu beschreiben...

Grüße
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.114 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 11:20
Ein "So basteln Sie sich eine XYZ-Anwendung"-Tutorial das ich zufällig über Google gefunden habe ist doch keine Dokumentation , auch wenn es von Embarcadero stammt. Finde ich.

Würde es in der Doku angesprochen werden, würde ich das noch vielleich gelten lassen. Aber das steht einfach nur so im Raum. Woher weiß ich, was noch für Arten von Fehlern nach oben geworfen werden können? Ich möchte nicht dort enden, aus Unwissenheit grundsätzlich Exceptions zu essen, nur weil Embarcadero nichts vernünftig dokumentiert hat (falls das denn der Fall sein sollte)...
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#4

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 11:37
Wichtig scheint mir das nur wenn Du auf verschiedene Exceptions unterschiedlich reagieren willst, was dann ja voraussetzt dass Du weist was Du wie behandeln will. Den Rest kannst Du ja über den else Zweig abfackeln.

Delphi-Quellcode:
procedure Tuwas(const s:String);
var
   i:Integer;
begin
  try
    i := StrToInt(s);
    Showmessage(FloatToStr(1/i));
  except
    ON E:Exception do
    begin
      if E is EZeroDivide then Showmessage('Divison durch 0')
      else Raise; // oder was auch sonst hier vorzusehen wäre
    end;
  end;
end;

procedure TForm3.Button1Click(Sender: TObject);
begin
  TuWas('0');
  TuWas('Nase');
end;
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.114 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 11:53
Wichtig scheint mir das nur wenn Du auf verschiedene Exceptions unterschiedlich reagieren willst
Vollkommen richtig.

Ich möchte ja nur überhaupt wissen, dass da etwas kommen kann! Meine Beschwerde ist bislang nur:
"Zufällig sah ich in diesem zusammenhangslosen Tutorial, dass diese Methode eine Exception werfen kann. Das steht weder in der Doku, noch ist es in der Implementation ersichtlich. Das darf nicht sein, Embarcadero!"
Weiterhin die Hoffnung, dass die Beschwerde unbegründet ist.


Kannst Du blöd finden oder nicht, ändert aber nichts daran, dass es die offizielle Doku ist.
Meinetwegen. Aber selbst das ist nicht vollständig. Das Teil kann genauso gut eine TDBXError-Exception werfen. Und die ist mit dem EDataBaseError nicht verwandt. Die fängt der Kerl in seinem Tutorial auch nicht. Und in der Doku vermerkt ist es natürlich auch nicht.

Geändert von Der schöne Günther ( 6. Jun 2013 um 11:58 Uhr)
  Mit Zitat antworten Zitat
sahimba

Registriert seit: 14. Nov 2011
Ort: Berlin, Hauptstadt der DDR
137 Beiträge
 
Delphi 10 Seattle Professional
 
#6

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 11:58
Witzigerweise kann das Ding auch noch ganz andere Exceptions werfen. Und die fängt der Tutorialersteller nicht.
Man "sollte" imho auch nur jene Exceptions behandeln, auf welche man auch wirklich (sinnvoll) reagieren kann. Im Zweifel lässt man sie eben ganz nach oben bubbeln.

Wobei es immer Ausnahmen von der Regel gibt und auch selten, ganz selten, ein Exceptionhandler sinnvoll sein kann, welcher wirklich alles schluckt. An dem Thema entzündeten sich fraglos schon Religionskriege.
  Mit Zitat antworten Zitat
Lemmy

Registriert seit: 8. Jun 2002
Ort: Berglen
2.366 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 11:50
Ein "So basteln Sie sich eine XYZ-Anwendung"-Tutorial das ich zufällig über Google gefunden habe ist doch keine Dokumentation , auch wenn es von Embarcadero stammt. Finde ich.
Kannst Du blöd finden oder nicht, ändert aber nichts daran, dass es die offizielle Doku ist.


Ich möchte nicht dort enden, aus Unwissenheit grundsätzlich Exceptions zu essen, nur weil Embarcadero nichts vernünftig dokumentiert hat (falls das denn der Fall sein sollte)...
wo isst Du Exceptions? Du reagierst auf EDatabaseError und der Rest wird an die gui geworfen (ist zumindest bei Delphi 7 so und wird auch hoffentlich in XEx nicht anders sein)
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 15. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#8

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 12:20
Also ein Code wie dieser macht überhaupt keinen Sinn:
Delphi-Quellcode:
try
   // Establish the connection.
   SQLConnection1.Connected := true;
   executeButton.Enabled := true;
   outputMemo.Text := 'Connection established!';
except
   on E: EDatabaseError do
      ShowMessage('Exception raised with message' + E.Message);
end;
1. Problem:
der Programmfaden läuft weiter obwohl das Öffnen der Datenbank erfolglos was.
In der Folge wird es im weiteren Verlauf zu einer weiteren Exception kommen.
2. Problem:
das Abfangen der Exception und das ShowMessage vernichtet wichtige Informationen zur Fehlersuche.
Es geht z.B. die genaue Exception-Klasse verloren.
Die Fehlermeldung "Exception raised with message" ist absolut Aussagelos, es steckt keine nützliche Information drin.
3. Problem:
durch das Abfangen der Exception, geht die Möglichkeit verloren die Exception automatisch in eine Logdatei zu schreiben.

Wie macht man es dann richtig?

1. Regel:
Exceptions nur dann abfangen, wenn man irgendwas zur Verbesserung beitragen kann.
Die Idee man könnte eine Exception durch abfangen irgendwie "reparieren" ist sowieso in 99% aller Fälle falsch.
Was man allerdings tun kann ist dem Benutzer möglichst gute Informationen zu geben was die Ursache b etrifft und wie er das Problem beheben kann.
Delphi-Quellcode:
try
   // Establish the connection.
   SQLConnection1.Connected := true;
   executeButton.Enabled := true;
   outputMemo.Text := 'Connection established!';
except
   on E: Exception do
   begin
      // dem Benutzer und dem Programmierer eine aussagekräftige Meldung geben
      // allgemeine Beschreibung zu Beginn der Meldung
      E.Message := 'Fehler beim Öffnen der Datenbank'#13#10+
         E.Message + #13#10 +
         // Details für Programmierer am Ende der Message
         SQLConnection1.ConnectionString;

      // um den Benutzer optimal zu unterstützen kann man den HelpContext setzen
      E.HelpContext := HELPCONTEXT_CONNECTION_FAILED;

      raise; // Exception neu auslösen, Exceptionklasse bleibt erhalten
   end;
end;
2. Regel:
nicht Exceptions abfangen und irgendwas mit ShowMessage anzeigen.
Showessage hat in dem Code nicht verloren.
Stellt dir vor die Exception tritt in einer Schleife mit >100 Durchläufen auf.
Ständig popt die gleiche Meldung auf; man kann das Programm nur noch abschiesen
3. Regel:
Man sollte raise wesentlich öfters verwenden als try...except .
In dem man eigene Exception-Klassen deklariert und diese dann raised kann man besondern in großen Programmen die Fehlerursache genauer lokalisiert.
4. Regel:
Das Prinzip der Informationanreicherung schachteln
Delphi-Quellcode:
procedure TDataModule.CalcTaxInternal(IdCompany:Integer);
begin
  // jede Menge komplizierter Code zur Steuerberechnung
  ...
end;

procedure TDataModule.CalcTax(IdCompany:Integer);
begin
  try
     CalcTaxInternal(IdCompany);
  except
   on E: Exception do
   begin
      E.Message := 'Fehler bei Steuerberechnung für Firma '+IntToStr(IdCompany)#13#10+
         E.Message:
      E.HelpContext := HELPCONTEXT_TAX_CALC_ERROR;
      raise; // Exception neu auslösen, Exceptionklasse bleibt erhalten
   end;
end;
Selbst bei einer Zugriffsverletzung innerhalb von CalcTaxInternal() bekommt der Benutzer und der Programmierer so eine gute Info wo das Problem ist.
Die eigentliche Steuerberechnung bleibt völlig frei von störenden try ... except .
fork me on Github

Geändert von sx2008 ( 6. Jun 2013 um 12:22 Uhr)
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#9

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 14:49
Dort finde ich:
Delphi-Quellcode:
try
   // Establish the connection.
   SQLConnection1.Connected := true;
   executeButton.Enabled := true;
   outputMemo.Text := 'Connection established!';
except
   on E: EDatabaseError do
      ShowMessage('Exception raised with message' + E.Message);
end;
Abgesehen davon, dass ich nicht einsehe, warum man die beiden Oberflächen-bezogenen Anweisungen nicht nach dem try-Block ausführen sollte
Naja, ganz einfach deshalb, weil die Ausführung nach dem except-Block ja ganz normal fortgesetzt wird. Da stünde dann „Connection established“, selbst wenn gar keine Verbindung aufgebaut werden konnte.

Ansonsten, da ich jetzt eine Weile mit Java arbeiten musste, gebe ich dir recht, dass Exceptions in Delphi besser dokumentiert sein könnten. Allerdings hatte ich in Delphi trotzdem nie Probleme damit (Ausnahme: Indy-Bibliothek, weil da einfach für alles eine Exception geworfen wird, selbst wenn es kein Fehler ist. Deshalb verwende ich die nicht mehr).

Wenn es dir wirklich nur darum geht, dass der Benutzer keine Fehler-Popups erhält, dann solltest du meiner Meinung nach einfach „Exception“ abfangen. Java-Checkstyle hat mir das nicht erlaubt, aber manchmal ist es nun mal wirklich genau das, was man will. Aber man sollte die Exception natürlich nicht einfach still schlucken, sondern an eine globale Fehlerbehandlungsmethode weiterleiten (z.B. zum loggen).

Oder unter Delphi gibt es noch eine weitere Möglichkeit, nämlich TApplication.OnException zu hooken. Das wäre sozusagen die letztmögliche Ebene, auf der eine Exception abgefangen werden kann, wenn alles andere versagt hat.

Die erste Methode kann trotzdem in manchen Situationen sinnvoll sein: Nehmen wir zum Beispiel mal an, dass unser Code alle Ordner rekursiv in einem Baum darstellen soll.

Delphi-Quellcode:
procedure VerzeichnisAuflisten(Verzeichnis: String);
begin
  for UnterVerzeichnis in Verzeichnis do
    VerzeichnisAuflisten(UnterVerzeichnis);
end;
Wenn jetzt ein Unterverzeichnis nicht eingelesen werden kann (aus welchem Grund auch immer), dann wollen wir ja wahrscheinlich trotzdem noch die anderen einlesen und nicht die ganze Operation abbrechen.

Delphi-Quellcode:
procedure VerzeichnisAuflisten(Verzeichnis: String);
begin
  try
    for UnterVerzeichnis in Verzeichnis do
      VerzeichnisAuflisten(UnterVerzeichnis);
  except
    on E: Exception do:
      Log(E);
  end;
end;

Geändert von Namenloser ( 6. Jun 2013 um 14:57 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.114 Beiträge
 
Delphi 10 Seattle Enterprise
 
#10

AW: Dokumentation und Exceptions - Wann muss ich was erwarten?

  Alt 6. Jun 2013, 15:28
Naja, ganz einfach deshalb, weil die Ausführung nach dem except-Block ja ganz normal fortgesetzt wird.
Klar, im Exception-Fall hätte ich (wenn sinnvoll) dann auch die Methode verlassen. Aber das ist wohl persönlicher Stil.

Genau Java hat mir das auch mehr oder weniger angewöhnt, das ist bislang das einzige, was ich aus anderen Programmiersprachen wirklich in Delphi vermisse: Entweder man muss die Exception fangen, oder die Methode macht es mit dem Schlüsselwort throws explizit deutlich (und die aufrufende Methode muss es fangen).

Oder unter Delphi gibt es noch eine weitere Möglichkeit, nämlich TApplication.OnException zu hooken
Klasse, das ist mir viel wert!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      

 

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 15:29 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