Objekt auf Übergabe prüfen.
Anbei ein konstruiertes Beispiel:
Delphi-Quellcode:
In der Zeile
function Test(sl: TStringList; Index: Integer): TObject;
begin Result := sl.Objects[Index]; //was hier Prüfen? sl.Delete(Index); end;
Delphi-Quellcode:
wird ein Objekt übergeben. Nun gehen wir mal davon aus, Index ist außer Bereich, also gibt es eine Fehlermeldung. Das ist auch so gewollt.
Result := sl.Objects[Index];
Nun weiter im Programm, als nächstes ist die Zeile
Delphi-Quellcode:
dran. Falls der Index zu hoch ist, wird es auch hier eine Fehlermeldung geben. Und das soll nicht sein. Eine Meldung ist ok, zwei zuviel.
sl.Delete(Index);
Jetzt bitte nicht fragen wieso hier Index nicht vorher überprüft wird, ist nur ein Beispiel. Wie bekommt man nun mit ob in der ersten Zeile alles richtig abgelaufen ist? Es geht nicht drum in der ersten Zeile eine Fehlermeldung abzufangen. Die soll kommen wenn Index falsch ist, nur will ich in dem Fall keine zwei gleiche Meldungen. Man könnte Result prüfen bevor man die zweite Zeile ausführt, nur wie? Auf nil? Und nun die Frage: muss man Result in dem Fall vorher nil zuweisen? Sieht irgendwie sonderbar aus.
Delphi-Quellcode:
begin
Result := nil; Result := sl.Objects[Index]; if Result <> nil then sl.Delete(Index); |
AW: Objekt auf Übergabe prüfen.
"Nun gehen wir mal davon aus, Index ist außer Bereich, also gibt es eine Fehlermeldung. Das ist auch so gewollt."
Kommt drauf an, was du mit Fehlermeldung meinst: a. Exception b. Rückgabewert = NIL Sofern es a ist, wird der Programmfluss unterbrochen und es wird zum ersten registrierten Exception Handler (SEH) gesprungen - dh. die zweite Zeile bei deinem Beispiel wird gar nicht erst ausgeführt. Wenns aber b ist, dann musst du selber eine Boundüberprüfung durchführen! |
AW: Objekt auf Übergabe prüfen.
Zitat:
Delphi-Quellcode:
begin
Result := nil; // Nutzlos, da Result gleich wieder überschrieben wird. Result := sl.Objects[Index]; // bei einer Execptiopn wird Result zwar nicht überschrieben, aber dann werden die nächsten Zeilen eh nicht ausgeführt if Result <> nil then // Wenn es den Index zwar gibt, aber in Objekt wirklich NIL drin steht, dann wird natürlich nicht gelöscht. sl.Delete(Index); |
AW: Objekt auf Übergabe prüfen.
So wäre es komplett richtig in diesem Kontext
Delphi-Quellcode:
Bei der Verwendung
function Test(sl: TStringList; Index: Integer): TObject;
begin // Ist Index OutOfRange wird eine Exception geworfen // gut so, denn dann ist bei diesem Befehl Schluss Result := sl.Objects[Index]; // Hier liegt eine mögliche Fehlerquelle, und darum schmeissen wir eine Exception, wenn das nicht passt if sl.OwnsObjects and Assigned( Result ) then raise Exception.Create( 'Das kann ich nicht bei einer TStringList mit OwnsObjects!' ); sl.Delete(Index); // Wenn bei der Rückgabe zwingend eine Instanz gefordert ist, dann kann hier nochmals eine Exception geworfen werden Assert( Assigned( Result ) ); // Oder eben if not Assigned( Result ) then raise Exception.Create( 'Es wird keine Instanz zurückgeliefert, obwohl das so sein muss!' ); end;
Delphi-Quellcode:
procedure foo;
var LObj : TObject; begin LObj := Test( MyStringList, 10 ); // wenn eine Exception beim Aufruf von Test auftritt, dann wird das hier drunter auch nicht mehr ausgeführt try // Hier irgendwas mit LObj machen finally LObj.Free; end; end; |
AW: Objekt auf Übergabe prüfen.
Noch richtiger wäre es IMO mit
Delphi-Quellcode:
am Funktionsanfang.
Assert(Assigned(sl));
|
AW: Objekt auf Übergabe prüfen.
Zitat:
Problematisch sind ja immer nur die Fälle, wo die Exception nicht da auftritt, wo diese eigentlich verursacht wurde, denn dann kann man sich einen Wolf suchen. Also wie in der Test-Prozedur, mit dem TStringList.OwnsObjects. |
AW: Objekt auf Übergabe prüfen.
@Aphton
Zitat:
@himitsu
Delphi-Quellcode:
Ich gebe zu, im Grunde ein Sicherheitsfanatiker zu sein, der die Hälfte der Zeit an einem Programm damit verbringt Fehler abzufangen noch bevor sie eine Exception auslösen. Somit fühle ich mich unwohl bei dem Gedanken eine Zeile ins offene Messer laufen zu lassen, in der Annahme, dass es nicht treffen wird, da es darüberfliegt.
..
Result := sl.Objects[Index]; // bei einer Execptiopn wird Result zwar nicht überschrieben, aber dann werden die nächsten Zeilen eh nicht ausgeführt @Sir Rufo Lassen wir mal
Delphi-Quellcode:
außen vorweg, dazu komme ich gleich.
sl.OwnsObjects
Assigned war auch meine erste Idee, hab es dann aber verworfen, denn entweder ich hab einen Gedankenfehler oder ...
Delphi-Quellcode:
Also entweder ich verstehe Assigned falsch oder es ist das Gleiche.
if o <> nil then ...
//und if Assigned(o) then ... Wenn ich nun das mache
Delphi-Quellcode:
dann hat o irgendeinen Wert, ist somit nicht NIL, aber Assigned gleich True, womit eine Abfrage ein falsches Ergebnis liefern würde.
var
o: TObject; begin Entweder ich sehe das falsch oder eine frische Objektvariable kann nicht mit NIL oder Assigned geprüft werden. Somit wäre bei
Delphi-Quellcode:
Result unkontrolliert, denn entweder wird ein Objekt zugewiesen oder kein Wert übergeben. In dem Fall ist der Wert wie vor der Zeile. Womit wir dann zu himitsus und deinem Vorschlag kommen - knallt es schon in der Zeile
Result := sl.Objects[Index];
Delphi-Quellcode:
, kann man danach auf jegliche Überprüfung verzichten, denn an der Stelle bricht die Funktion ab. Wie gesagt, ich hab nichts dagegen, nur will ich keine zwei gleiche Fehlermeldungen nacheinander.
sl.Objects[Index]
Zu
Delphi-Quellcode:
. In Delphi 7 gibt es die noch nicht. Gehe ich richtig in der Annahme, dass inzwischen die Objekte automatisch freigegeben werden?
sl.OwnsObjects
|
AW: Objekt auf Übergabe prüfen.
Du hast einen Gedankenfehler ;)
Delphi-Quellcode:
oder hier der Ablauf mit einer Exception in Test
function Test( sl : TStringList; Index : Integer) : TObject;
begin Result := sl.Objects[Index]; sl.Delete(Index); end; procedure foo; var o : TObject; begin o := Test( MyStringList, 1 ); // o hat jetzt eine Referenz aus der StringList, // oder es kam eine Exception in Test und der Rest hier wird auch nicht abgearbeitet DoSomethingWith( o ); end;
Delphi-Quellcode:
und hier ohne Exception
foo
o := Test( MyStringList, -1 ); Result := sl.Objects[Index]; // Knallt und gibt eine Exception // fertig mit Test // fertig mit foo // Eine MessageBox mit der Exception
Delphi-Quellcode:
foo
o := Test( MyStringList, 1 ); Result := sl.Objects[Index]; sl.Delete( Index ); // fertig mit Test DoSomethingWith( o ); // fertig mit foo |
AW: Objekt auf Übergabe prüfen.
Wie das abläuft dachte ich mir schon bevor ich die erste Frage gestellt habe, ich wollte nur wissen was Stand der Programmiertechnik ist. Wie gesagt, ob das nun falsch oder richtig ist, ich baue überall im Programm Abfragen, noch bevor eine Exception kommt. Ich denke mir, ich mache oft zu viel des Guten, so dass hier der erste Reflex die Frage war, wie kann ich die zweite Zeile abfangen?
|
AW: Objekt auf Übergabe prüfen.
Wenn dir der Ablauf klar ist, dann ist doch aber die Frage obsolet.
Denn du willst ja die 2. Exception verhindern, die aber schon durch die 1. Exception verhindert wird, weil da eben eine Exception geworfen wird. Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:47 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