Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Listenklasse für beliebige Datenklassen (RTTI) (https://www.delphipraxis.net/150690-listenklasse-fuer-beliebige-datenklassen-rtti.html)

Schorschi5566 23. Apr 2010 21:12


Listenklasse für beliebige Datenklassen (RTTI)
 
Hallo liebe DPler,

seit kurzem habe ich nun auch Delphi 2010 und wollte natürlich mal was mit den neuen Features machen.

Es geht um eine Listenklasse, der man von außen eine Datenklasse übergibt ohne dass sie diese kennen würde.

Sollte man ja mit RTTI was machen können. :)

Eine Anforderung ist, dass ich nicht ständig irgendwo casten möchte.

Das Handling soll etwa so aussehen:

Delphi-Quellcode:
type
  TDataObject = class(TPersistent)
  public
    MeinString, DeinString: String;
    MeinInteger: Word;
  end;

.
.
.


procedure TForm1.Button1Click(Sender: TObject);
var
  List: TUniList;
  DataInterface, Data: TDataObject;
begin
  DataInterface := TDataObject.Create;
  List := TUniList.Create(DataInterface);

  Data := TDataObject.Create;
  Data.MeinString := 'Anfang';
  Data.MeinInteger := 200;
  List.Add(Data);
  Data.MeinString := 'Ende';
  Data.MeinInteger := 100;
  List.Add(Data);
  List.First;
  showmessage(DataInterface.MeinString + ' ' + IntToStr
      (DataInterface.MeinInteger)); // Hier kommt "Anfang 200"
  List.Last;
  showmessage(DataInterface.MeinString + ' ' + IntToStr
      (DataInterface.MeinInteger)); // Hier kommt "Ende 100"

  List.Free;
  Data.Free;
end;
Die Listenklasse dazu sieht bis jetzt so aus (fehlt noch die Hälfte)...

Delphi-Quellcode:
  TUniList = class(TObject)
    FData: TObjectList;
    FObj: TObject; // das Interface nach draussen
    FClass: TClass;
    procedure AssignTo(Item: TObject);
  public
    constructor Create(DataInterface: TObject);
    destructor Destroy;
    procedure Add(Item: TObject);
    procedure First;
    procedure Last;
  end;

.
.
.

procedure TUniList.Add(Item: TObject);
var
  Obj: TObject;
  context: TRttiContext;
  typinfo: TRttiType;
  field: TRttiField;
begin
  // Object an Liste anhängen
  Obj := FClass.NewInstance; // neue Instanz von der Containerklasse erzeugen
  context := TRttiContext.Create;
  typinfo := context.GetType(FClass);
  for field in typinfo.GetFields do
  begin
    field.SetValue(Obj, field.GetValue(Item));
  end;
  FData.Add(Obj);
  context.Free;
end;

procedure TUniList.AssignTo(Item: TObject);
var
  context: TRttiContext;
  typinfo: TRttiType;
  field: TRttiField;
begin
  context := TRttiContext.Create;
  typinfo := context.GetType(FClass);
  for field in typinfo.GetFields do
  begin
    field.SetValue(FObj, field.GetValue(Item));
  end;
  context.Free;
end;

constructor TUniList.Create(DataInterface: TObject);
begin
  FData := TObjectList.Create;
  FClass := DataInterface.ClassType;
  FObj := DataInterface;
end;

destructor TUniList.Destroy;
begin
  FData.Free;
  FObj.Free; // wird hier richtig frei gegeben oder gibt's ein Speicherleck?
end;

procedure TUniList.First;
var
  Obj: TObject;
begin
  Obj := FData.First;
  AssignTo(Obj); // Werte aus Liste in DataInterface schreiben
end;

procedure TUniList.Last;
var
  Obj: TObject;
begin
  Obj := FData.Last;
  AssignTo(Obj); // Werte aus Liste in DataInterface schreiben
end;
Die Sache mit dem DataInterface habe ich gemacht, weil es mir bisher nicht gelungen ist innerhalb der Listenklasse ein Objekt vom Typ TDataObject zu generieren und auch zurückgeben zu können. (Generieren schon, siehe TUniList.Add aber eben nicht zurückgeben)

Kann man mit RTTI auch zur Laufzeit den Rückgabewert einer function beeinflussen?


Wäre nett, wenn sich das mal einer der Cracks ansehen könnte und mir sagt ob das so passt oder völlig daneben ist oder viel einfacher geht. :P


Viele Grüße,
Schorsch

mjustin 24. Apr 2010 07:40

Re: Listenklasse für beliebige Datenklassen (RTTI)
 
Das Problem ist mit RTTI nicht lösbar.

Uwe Raabe 24. Apr 2010 09:25

Re: Listenklasse für beliebige Datenklassen (RTTI)
 
Warum nicht gleich eine generische Liste? TObjectList<T> kümmert sich auch automatisch um die Freigabe der enthaltenen Objekte.

Delphi-Quellcode:
uses
  Generics.Collection;

type
  TDataObject = class(TPersistent)
  public
    MeinString, DeinString: String;
    MeinInteger: Word;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  List: TObjectList<TDataObject>;
  Data: TDataObject;
begin
  List := TObjectList<TDataObject>.Create;
  try

    Data := TDataObject.Create;
    Data.MeinString := 'Anfang';
    Data.MeinInteger := 200;
    List.Add(Data);

    Data.MeinString := 'Ende';
    Data.MeinInteger := 100;
    List.Add(Data);

    Data := List.First;
    showmessage(Data.MeinString + ' ' + IntToStr
        (Data.MeinInteger)); // Hier kommt "Anfang 200"

    Data := List.Last;
    showmessage(Data.MeinString + ' ' + IntToStr
        (Data.MeinInteger)); // Hier kommt "Ende 100"

  finally
    List.Free;
  end;
end;

Schorschi5566 24. Apr 2010 19:41

Re: Listenklasse für beliebige Datenklassen (RTTI)
 
Hallo zusammen,

danke für Eure Antworten.

@Uwe:

Zitat:

Zitat von Uwe
Warum nicht gleich eine generische Liste? TObjectList<T>

Weil ich die Sache mit <T> schlicht nicht kannte. :D Aber danke für den Hinweis.

Würde das denn auch mit einer von TObjectList abgeleiteten und erweiterten Listenklasse funktionieren? Wie würden dann beispielsweise die Funktionen Next und Prev das aktuelle Listenobjekt zurückgeben ohne von der Datenklasse zu wissen?


Ich habe mal mit meinem Ansatz weitergemacht und IndexOf(Field, Value) und Sort(Field) mit RTTI implementiert. Das finde ich schon sehr schnucklig. Eine Funktion kümmert sich um alle Felder.

Wenn sowas jetzt auch mit generischen Listen geht, gehen mir langsam die Ideen aus, wie man RTTI sinnvoll einsetzen kann. :mrgreen:


Viele Grüße,
Schorsch


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