Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi TObjectList-Object da, aber beim Zugriff Stack-Overflow (https://www.delphipraxis.net/187942-tobjectlist-object-da-aber-beim-zugriff-stack-overflow.html)

Captnemo 18. Jan 2016 14:27

TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Hi,

ich habe eine TObjectList nach diesem Schema:
Delphi-Quellcode:
type
  TTemperatur=class
  private
    FTemp: Extended;
    FId: string;
    procedure SetId(const Value: string);
    procedure SetTemp(const Value: Extended);
  public
    constructor Create;
    procedure WriteToStream(st: TStream);
    procedure LoadFromStream(st: TStream);
  published
    property Id: string read FId write SetId;
    property Temp: Extended read FTemp write SetTemp;
  end;

type
  TTemperaturList=class(TObjectList)
    function getItem(index: Integer): TTemperatur; virtual;
    procedure setItem(index: Integer; Temperatur: TTemperatur); virtual;
  public
    property Items[index: Integer]: TTemperatur read getItem write setItem; default;
    procedure Insert(index: Integer; Temperatur: TTemperatur); virtual;
    function Add(Temperatur: TTemperatur): Integer; virtual;
    function Remove(Temperatur: TTemperatur): Integer; virtual;
    function IndexOf(Temperatur: TTemperatur): Integer; virtual;
    function First: TTemperatur; virtual;
    function Last: TTemperatur; virtual;
    procedure WriteToStream(st: TStream);
    procedure LoadFromStream(st: TStream);
    function IndexOfId(value: string): Integer; virtual;
  end;

type
  TRaspberry=class
  private
    FName: string;
    FTemp: TTemperaturList;
    FIP: string;
    procedure SetIP(const Value: string);
    procedure SetName(const Value: string);
    procedure SetTemp(const Value: TTemperaturList);
  public
    constructor Create;
    destructor Destroy;
    procedure WriteToStream(st: TStream);
    procedure LoadFromStream(st: TStream);
  published
    property Name: string read FName write SetName;
    property IP: string read FIP write SetIP;
    property Temp: TTemperaturList read FTemp write SetTemp;
  end;

type
  TRaspberryList=class(TObjectList)
    function getItem(index: Integer): TRaspberry; virtual;
    procedure setItem(index: Integer; Raspberry: TRaspberry); virtual;
  public
    property Items[index: Integer]: TRaspberry read getItem write setItem; default;
    procedure Insert(index: Integer; Raspberry: TRaspberry); virtual;
    function Add(Raspberry: TRaspberry): Integer; virtual;
    function Remove(Raspberry: TRaspberry): Integer; virtual;
    function IndexOf(Raspberry: TRaspberry): Integer; virtual;
    function First: TRaspberry; virtual;
    function Last: TRaspberry; virtual;
    procedure WriteToFile(Filename: string);
    procedure LoadFromFile(Filename: string);
    function IndexOfIP(value: string): Integer; virtual;
  end;
Explizit geht es um die Funktion:
Delphi-Quellcode:
function TTemperaturList.IndexOfId(value: string): Integer;
var
  I: Integer;
begin
  Result:=-1;
  for I := 0 to self.Count-1 do
    if self[I].Id=value then
    begin
      Result:=I;
      Exit;
    end;
end;
der TTemperaturList.

Jetzt sollen mit folgender Prozedur TTemperatur-Items hinzugefügt, bzw. wenn sie schon vorhanden sind, geändert werden:
Delphi-Quellcode:
procedure TfrmMain.btn1Click(Sender: TObject);
var
  r, t: integer;
  Raspberry: TRaspberry;
  Temp: TTemperatur;
  FIP, FId: string;
  FTemperatur: Extended;
begin
  FIP:='192.168.0.110';
  FId:='28-000444e3ba3ff';
  FTemperatur:=19.937;
  r:=FRaspberrys.IndexOfIP(FIP);
  if r>-1 then
  begin
    Raspberry:=FRaspberrys[r];
  end else begin
    Raspberry:=TRaspberry.Create;
    FRaspberrys.Add(Raspberry);
  end;
  if Raspberry<>nil then
  begin
    t:=Raspberry.Temp.IndexOfId(FId); //<---Hier tritt beim zweiten durchlauf dann die Exception auf.
    if t>-1 then
    begin
      Temp:=Raspberry.Temp[t];  
    end else begin
      Temp:=TTemperatur.Create;
      Raspberry.Temp.Add(Temp);
    end;
    if Temp<>nil then
    begin
      Temp.Id:=FId;
      Temp.Temp:=FTemperatur;
    end;
  end;
end;
Ein TRaspberry wird manuell erzeugt, ist also vorhanden.

Beim TTemperaturList.IndexOfId(value: string) kommt es beim zweiten Aufruf der btn1Click zu einem Stackoverflow. Klar beim ersten mal wird das neue Objekt TTemperatur angelegt, weil eben noch keines vorhanden ist.
Beim zweiten Mal müsste er es ja finden, da die Id die gleich ist. Komischerweise wird in der IndexOfId als Count auch 1 ausgegeben, aber auf das Object kann ich nicht zugreifen. Also irgendwo hab ich einen Denkfehler, aber ich finde ich einfach nicht.

mjustin 18. Jan 2016 14:43

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Zitat:

Zitat von Captnemo (Beitrag 1327332)
ich habe eine TObjectList nach diesem Schema:

Einen Grund für den Absturz konnte ich noch nicht sehen. Vielleicht können wir es besser reproduzieren wenn der Code auf ein minimales Beispiel reduziert wird?

Robuster wäre es die Containerklasse nicht von der Klasse TObjectList abzuleiten sondern eine interne (private) TObjecList Instanz zu benutzen. Das entkoppelt die API der TObjectList und sichert den Client-Code besser gegen "versehentliche" Verwendung von TObjectList Methoden ab. Das könnte auch für die konkrete Fehlersuche hilfreich sein.

Captnemo 18. Jan 2016 14:47

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Danke für deine Hilfe. Den eigentlichen Fehler habe ich mittlerweile gefunden: es war lediglich ein fehlendes inherited beim Zugriff auf das TTemperaturobjekt.

Zitat:

Zitat von mjustin (Beitrag 1327335)
wäre es die Containerklasse nicht von der Klasse TObjectList abzuleiten sondern eine interne (private) TObjecList Instanz zu benutzen. Das entkoppelt die API der TObjectList und sichert den Client-Code besser gegen "versehentliche" Verwendung von TObjectList Methoden ab. Das könnte auch für die konkrete Fehlersuche hilfreich sein.

Aber wenn du mir das noch mal anders erläutern könntest, wäre ich dir sehr dankbar, denn ich weiß im Augenblick nicht was du damit meinst.

mjustin 18. Jan 2016 14:53

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Bei mir sind Container immer z.B. so aufgebaut:

Delphi-Quellcode:
type
  TTemperaturList=class(TObject)
  private
    Liste: TObjectList;

    ...
   
  public
    constructor Create;
    destructor Destroy; override;
Von aussen hin kann ich dann gezielt nur die von meiner Klasse definierten Funktionen und Prozeduren aufrufen. Dass innen eine TObjectList oder etwas anderes enthalten ist, soll der Client nicht sehen können.

Jumpy 18. Jan 2016 14:57

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Ich denke er meint, dass du eine Objektlist in deiner neuen Klasse kapselst. So kann man ganz gut die eventuelle Object-Casterei verbergen.

Edit:Und war sogar selber schneller als ich...

Delphi-Quellcode:
type
  TTemperaturList=class
    ObjectList:TObjectList;
  public
    constructor create;
    function count:integer;
  end;

TTemperaturList.create;
begin
  ObjectList:=TObjectList.create;
end;

TTemperaturList.count:integer;
begin
  Result:=ObjectList.Count;
end;

Andere Bemerkung, wenns erlaubt ist: Was mich an deinem Klassenkonstrukt stört ist was für verschiedene Dinge nicht alles Temp heißen. Da hat ich nämlich auch Probleme deinen QT nachzuvollziehen.

mjustin 18. Jan 2016 15:05

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Delphi-Quellcode:
type
  TTemperaturList=class(TObjectList)
    function getItem(index: Integer): TTemperatur; virtual;
    procedure setItem(index: Integer; Temperatur: TTemperatur); virtual;
  public
    property Items[index: Integer]: TTemperatur read getItem write setItem; default;
    procedure Insert(index: Integer; Temperatur: TTemperatur); virtual;
    function Add(Temperatur: TTemperatur): Integer; virtual;
    function Remove(Temperatur: TTemperatur): Integer; virtual;
    ...
Die Methoden getItem und setItem brauchen nicht als published declariert werden, eventuell fehlt hier das private. Published wird nicht benötigt ausser man möchte die Klasse über das Delphi DFM Streaming oder klassische RTTI ansprechen.

SProske 18. Jan 2016 15:12

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Da der TE wohl XE4 verwendet, wäre sicher auch die generische Objektliste aus der Unit System.Generics.Collections einen Blick Wert.
Damit könnte man sich die Schreibarbeit für Add/Remove/IndexOf etc. ersparen.

Captnemo 18. Jan 2016 15:25

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
@mjustin:
das Private fehlt tatsächlich. Eigentlich kommen bei mir die Getter und Setter immer in Private, hatte ich lediglich vergessen. (hätte bei dem fehlenden Inherited aber nichts geändert).
Aber ich weiß jetzt was du meinst.

Klar kann man das auch über Generics verwenden. Aber ich habe mich so an meine ObjectList gewöhnt....

Und, zugegeben, der Variablenname Temp ist sicherlich nicht der schlaueste, aber man kann das schon lesen ;)

Sir Rufo 18. Jan 2016 15:50

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Nur so als Tip:

Wenn man Klassen mit Stream-Funktionen ausstattet, dann sollte man auch immer das Interface Delphi-Referenz durchsuchenIStreamPersist an die Klasse heften.

Macht auf jeden Fall das Leben leichter ;)

freimatz 18. Jan 2016 16:15

AW: TObjectList-Object da, aber beim Zugriff Stack-Overflow
 
Zitat:

Zitat von Captnemo (Beitrag 1327338)
Zitat:

Zitat von mjustin (Beitrag 1327335)
wäre es die Containerklasse nicht von der Klasse TObjectList abzuleiten sondern eine interne (private) TObjecList Instanz zu benutzen. Das entkoppelt die API der TObjectList und sichert den Client-Code besser gegen "versehentliche" Verwendung von TObjectList Methoden ab. Das könnte auch für die konkrete Fehlersuche hilfreich sein.

Aber wenn du mir das noch mal anders erläutern könntest, wäre ich dir sehr dankbar, denn ich weiß im Augenblick nicht was du damit meinst.

Siehe auch:
http://clean-code-developer.de/die-g...heritance_FCoI


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:05 Uhr.
Seite 1 von 3  1 23      

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