Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Objekt auf Übergabe prüfen. (https://www.delphipraxis.net/178665-objekt-auf-uebergabe-pruefen.html)

Popov 20. Jan 2014 13:26

Objekt auf Übergabe prüfen.
 
Anbei ein konstruiertes Beispiel:
Delphi-Quellcode:
function Test(sl: TStringList; Index: Integer): TObject;
begin
  Result := sl.Objects[Index];
  //was hier Prüfen? 
  sl.Delete(Index);
end;
In der Zeile
Delphi-Quellcode:
Result := sl.Objects[Index];
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.

Nun weiter im Programm, als nächstes ist die Zeile
Delphi-Quellcode:
sl.Delete(Index);
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.

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);

Aphton 20. Jan 2014 13:30

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!

himitsu 20. Jan 2014 13:30

AW: Objekt auf Übergabe prüfen.
 
Zitat:

Zitat von Popov (Beitrag 1244542)
Nun weiter im Programm, als nächstes ist die Zeile sl.Delete(Index); 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.

Das Erste ist doch eine Exception und keine "Meldung", also kommt er da beim Zweiten garnicht mehr an?

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);

Sir Rufo 20. Jan 2014 14:19

AW: Objekt auf Übergabe prüfen.
 
So wäre es komplett richtig in diesem Kontext
Delphi-Quellcode:
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;
Bei der Verwendung
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;

DeddyH 20. Jan 2014 14:23

AW: Objekt auf Übergabe prüfen.
 
Noch richtiger wäre es IMO mit
Delphi-Quellcode:
Assert(Assigned(sl));
am Funktionsanfang.

Sir Rufo 20. Jan 2014 14:43

AW: Objekt auf Übergabe prüfen.
 
Zitat:

Zitat von DeddyH (Beitrag 1244554)
Noch richtiger wäre es IMO mit
Delphi-Quellcode:
Assert(Assigned(sl));
am Funktionsanfang.

Nein, das ist in diesem Fall nicht notwendig, denn dann wird in der Test-Prozedur auch gleich zu Anfang eine Exception geworfen.
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 Delphi-Referenz durchsuchenTStringList.OwnsObjects.

Popov 20. Jan 2014 18:37

AW: Objekt auf Übergabe prüfen.
 
@Aphton
Zitat:

Kommt drauf an, was du mit Fehlermeldung meinst:
a. Exception
b. Rückgabewert = NIL
Das ist es ja, es ist vorerst ein konstruiertes Beispiel. Wäre der Rückgabewert NIL, müsste man den nicht vorher zuweisen. Exception? Kann sein, vermutlich, aber entweder man überprüft jedes mal vorher individuell was zurück kommen könnte, oder man ist auf alles vorbereitet.

@himitsu
Delphi-Quellcode:
..
  Result := sl.Objects[Index]; // bei einer Execptiopn wird Result zwar nicht überschrieben, aber dann werden die nächsten Zeilen eh nicht ausgeführt
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.

@Sir Rufo

Lassen wir mal
Delphi-Quellcode:
sl.OwnsObjects
außen vorweg, dazu komme ich gleich.

Assigned war auch meine erste Idee, hab es dann aber verworfen, denn entweder ich hab einen Gedankenfehler oder ...
Delphi-Quellcode:
  if o <> nil then ...

//und

  if Assigned(o) then ...
Also entweder ich verstehe Assigned falsch oder es ist das Gleiche.

Wenn ich nun das mache
Delphi-Quellcode:
var
  o: TObject;
begin
dann hat o irgendeinen Wert, ist somit nicht NIL, aber Assigned gleich True, womit eine Abfrage ein falsches Ergebnis liefern würde.

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 := sl.Objects[Index];
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
Delphi-Quellcode:
sl.Objects[Index]
, 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.

Zu
Delphi-Quellcode:
sl.OwnsObjects
. In Delphi 7 gibt es die noch nicht. Gehe ich richtig in der Annahme, dass inzwischen die Objekte automatisch freigegeben werden?

Sir Rufo 20. Jan 2014 18:50

AW: Objekt auf Übergabe prüfen.
 
Du hast einen Gedankenfehler ;)

Delphi-Quellcode:
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;
oder hier der Ablauf mit einer Exception in Test
Delphi-Quellcode:
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
und hier ohne Exception
Delphi-Quellcode:
foo
  o := Test( MyStringList, 1 );
    Result := sl.Objects[Index];
    sl.Delete( Index );
    // fertig mit Test
  DoSomethingWith( o );
// fertig mit foo

Popov 20. Jan 2014 21:40

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?

Sir Rufo 20. Jan 2014 21:53

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:

Zitat von Popov (Beitrag 1244542)
Nun gehen wir mal davon aus, Index ist außer Bereich, also gibt es eine Fehlermeldung. Das ist auch so gewollt.

Nun weiter im Programm, als nächstes ist die Zeile
Delphi-Quellcode:
sl.Delete(Index);
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.

Jetzt bitte nicht fragen wieso hier Index nicht vorher überprüft wird, ist nur ein Beispiel.

Den Index würde ich auch nicht prüfen, der wird von der StringList geprüft und wirft eine Exception, wenn es nicht passt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:47 Uhr.
Seite 1 von 2  1 2      

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