Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi sicherere Klassen? (https://www.delphipraxis.net/144082-sicherere-klassen.html)

himitsu 29. Nov 2009 19:10


sicherere Klassen?
 
Zuersteinmal: diese Idee hab ich mir quasi vom .Free abgeguckt :nerd:

Spricht eigentlich etwas dagegen Klasseninstanzen, welche auf NIL stehen, teilweise auch mal mit zu behandeln und das Programm nicht immer gleich in Exceptions laufen zu lassen?
Zitat:

---------------------------
Project1
---------------------------
Zugriffsverletzung bei Adresse 0044C86C in Modul 'Project1.exe'. Lesen von Adresse 00000072.
---------------------------
OK
---------------------------
Speziell geht es zwar um mein kleines himXML (aber es ist mehr 'ne allgemeine Frage),
wo man z.B. N:=XML.Node[...].Node[...]; aufrufen könnte
und wenn nun das erste Node nicht existiert und auch kein xoNodeAutoCreate definiert ist,
dann würde dort NIL zurückgegeben und somit eine Exception ausgelöst.

Wenn jetzt das NIL aber mindestens bei "wichtigen" Leseoperationen ausgewertet würde, dann käme hierbei nicht zu einer Exception.

Nun die Frage: Wäre soein Verhalten hinnehmbar, oder sollte man es lieber beim alten/normalen Verhalten (mit Exception) belassen?

(es geht hier um billige Objekte und nicht um Interfaces oder so)

sx2008 30. Nov 2009 01:11

Re: sicherere Klassen?
 
Eine erste Sicherheitsmassnahme wäre:
Delphi-Quellcode:
function TXMLNode.Irgendwas:TDatentyp;
begin
  Assert(Assigned(self), 'TXMLNode.Irgendwas');
  ...
end;
Die Assertion gibt einen wichtigen Hinweis zur Fehlersuche;
auch dann wenn kein Debugger verfügbar ist.

Man kann auch dafür sorgen, dass es keine NIL-Objekte gibt indem man
immer eine Instanz erzeugt.
Jedes grössere Programm braucht eine Log-Ausgabe, die aber abschaltbar sein sollte.
Im ganzen Programm finden sich dann solche Zeilen:
Delphi-Quellcode:
if Assigned(LogObj) then
  LogObj.WriteMessage('irgendwas');
Anstatt nun überall zu prüfen, ob es das LogObjekt gibt, erzeugt man
grundsätzlich ein LogObjekt einer speziellen Klasse.
Es gibt dann die Klasse TCustomLogger und davon abgeleitet TFileLogger und TNullLogger.
Delphi-Quellcode:
if ParamStr(1)='/nolog' then
  LogObj := TNullLogger.Create
else
  LogObj := TFileLogger.Create(dateiname_logfile);
Jetzt kann man gefahrlos alle Methoden des LogObjekts aufrufen,
weil sichergestellt ist, dass immer ein gültiges Objekt erzeugt wurde.

Dieses Null-Object Design Pattern lässt
sich auch auf XMLNode Objekte übertragen.

himitsu 1. Dez 2009 11:43

Re: sicherere Klassen?
 
Sowas wie mit dem Null-Objekt wollte ich nicht einführen, denn dann geht sowas wie Assigned (beim Anwender) nicht mehr.

Aber das mit den Assertions werde ich zumindestens implementieren und die Properties ohne Getter werde ich nur im Fall von aktiven Assertions umleiten. :)

Stevie 1. Dez 2009 12:16

Re: sicherere Klassen?
 
Die Frage ist ja, was erwartet man, wenn man auf ein Element zugreift, welches es garnicht gibt?
Bei deinem Beispiel zumindest würde ja eigentlich schon beim Getter der Property Nodes ein Index out of bounds erwarten, wenn ich dort auf eine Node zugreifen möchte, die es nicht gibt. Wird über eine anderen Parameter darauf zugegriffen (hab deine Xml Implementierung nicht im Kopf) müsste man sich fragen: gibt es use cases, wo ich als Ergebnis nil zurückbekommen möchte (mit der Aussage, die node gibt es nicht) oder einen Fehler und ich muss vorher überprüfen, ob es eine bestimmte Node gibt.
Wenn du allerdings eine Implementierung wie bei TObject.Free benutzt, kann es sein, dass sich die Fehler nur verschieben, Beispiel:
Delphi-Quellcode:
N:=XML.Node[...].Node[...];
N.Value := 'my new node';
Angenommen der Setter von Value hat so einen Mechanismus, dann gibt es hier keine Zugriffverletzung, aber es wird einfach nix gemacht und an einer anderen Stelle krachts evtl oder es gibt einen Datenverlust.

himitsu 1. Dez 2009 12:36

Re: sicherere Klassen?
 
Wenn ich jetzt das NIL beachte und bei Lesezugriffen entsprechend behandle, dann würde hier
N:=XML.Node[...].Node[...]; (den ersten Node gibt es schon nicht)

das NIL durch das zweite Node durchgereicht und man könnte sowas machen
Delphi-Quellcode:
N := XML.Node['...'].Node['...'];
if not Assigned(N) then ERROR;
es würde also praktisch diesem entsprechen
Delphi-Quellcode:
N := XML.Node['...\...'];
if not Assigned(N) then ERROR;

Gut, jetzt hatte ich mich erstmal entschieden intern Asserts einzuführen und wenn sozusagen das zweite Node aufgerufen würde, dann wäre dort ja vom Ersten das NIL als eingang und würde dann eine EAssert auslösen, wenn assertions aktiviert sind, ansonsten würde sich dann eventuell irgendeine Folgeexteption bemerkbar machen ... meißt wohl "Zugriffverlezung bei Ardresse $000000xx" oder so.

Statt dem NIL als Result immer gleich mit einer Exception um mich zu werfen halte ich nun auch nicht immer für sonderlich angebracht. :gruebel:

HeikoAdams 1. Dez 2009 13:49

Re: sicherere Klassen?
 
Ich formuliere es mal ein wenig provokant, weil ich es selber bei selbgeschriebenen Komponenten so handhabe.

Bei Settern prüfen ich die übergebenen Werte nur auf formale Korrektheit und werfe ggf. mit Fehlern um mich. Wenn ein Getter oder Setter auf nich initialisierte Properties zugreifen soll, dann lasse ich es ruhig krachen. Es ist nich mein Job, die Faulheit/Schlampigkeit des anderen Programmierers abzufangen. 8-) Abgesehen davon erwarte ich von Programmierern, dass sie ihre Sachen testen, bevor sie sie auf die Menschheit loslassen. Und spätestens beim testen sollten solche Schludrigkeiten auffallen.

DeddyH 1. Dez 2009 14:14

Re: sicherere Klassen?
 
Das sehe ich ähnlich. Die Kunst ist allerdings, die Fehlermeldungen so zu formulieren, dass sie auch auf den tatsächlichen Fehler hindeuten. Ich sehe öfter mal so etwas(fiktives Beispiel):
Delphi-Quellcode:
try
  DoSomething;
except
  MessageBox(0,'Something went wrong',nil,0);
end;
Das finde ich nicht sonderlich informativ, gerade wenn das an mehreren Stellen so gehandhabt wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:37 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