Einzelnen Beitrag anzeigen

Schorschi5566

Registriert seit: 6. Feb 2006
197 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#1

Listenklasse für beliebige Datenklassen (RTTI)

  Alt 23. Apr 2010, 21:12
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.


Viele Grüße,
Schorsch
Uwe
  Mit Zitat antworten Zitat