Einzelnen Beitrag anzeigen

Catweasel77

Registriert seit: 29. Apr 2019
9 Beiträge
 
#1

Eine Frage zu Generics in generischen Listen

  Alt 5. Mai 2019, 15:30
Delphi-Version: 10.2 Tokyo
Hallo

Ich bin gerade dabei mich mit Generics zu beschaeftigen. Zum Teil klappt das auch ganz gut, aber ein kleines Problem hab ich noch bei dem ich nicht durchblicke. Hoffentlich kann mir jemand weiterhelfen und ein paar Tipps geben.

Nehmen wir an ich moechte eine Klasse fuer Datentypen haben mit der Faehigkeit aus einem Stream zu lesen, bzw. in Einen zu schreiben und den Wert als string auszugeben. Dazu habe ich eine generische Klasse erstellt und die jeweiligen Methoden zur Stringumwandlung (und beim string Typ das streaming) ueberschrieben:

Delphi-Quellcode:
unit UDataTypes;

interface

uses
  SysUtils, Classes;

type
  IDataIO=interface(IInterface)
    function GetVString: string;
    procedure LoadFromStream(AStream:TFileStream);
    procedure SaveToStream(AStream:TFileStream);
    property VString : string read GetVString;
  end;

type
  TDataTypeGeneric<TDataType>=class(TInterfacedObject, IDataIO)
  private
    FData : TDataType;
    function GetData: TDataType;
    procedure SetData(const Value: TDataType);
  protected
    function GetVString: string;virtual;abstract;
  public
    procedure LoadFromStream(AStream:TFileStream);virtual;
    procedure SaveToStream(AStream:TFileStream);virtual;
    property Data : TDataType read GetData write SetData;
    property VString : string read GetVString;
  end;

  TIntegerClass=class(TDataTypeGeneric<integer>)
  private
  protected
    function GetVString: string;override;
  public
  end;

  TFloatClass=class(TDataTypeGeneric<extended>)
  private
  protected
    function GetVString: string;override;
  public
  end;

  TBooleanClass=class(TDataTypeGeneric<boolean>)
  private
  protected
    function GetVString: string;override;
  public
  end;

  TStringClass=class(TDataTypeGeneric<string>)
  private

  protected
    function GetVString: string;override;
  public
    procedure LoadFromStream(AStream:TFileStream);override;
    procedure SaveToStream(AStream:TFileStream);override;
  end;


implementation

{ TDataTypeGeneric<TDataType> }


function TDataTypeGeneric<TDataType>.GetData: TDataType;
begin
Result := FData;
end;

procedure TDataTypeGeneric<TDataType>.LoadFromStream(AStream: TFileStream);
begin
AStream.Read(FData,SizeOf(FData));
end;

procedure TDataTypeGeneric<TDataType>.SaveToStream(AStream: TFileStream);
begin
AStream.Write(FData,SizeOf(FData));
end;

procedure TDataTypeGeneric<TDataType>.SetData(const Value: TDataType);
begin
FData := Value;
end;


{ TIntegerClass }

function TIntegerClass.GetVString: string;
begin
Result := IntToStr(FData);
end;


{ TFloatClass }

function TFloatClass.GetVString: string;
begin
Result := FloatToStr(FData);
end;


{ TBooleanClass }

function TBooleanClass.GetVString: string;
begin
Result := BoolToStr(FData,true);
end;


{ TStringClass }

function TStringClass.GetVString: string;
begin
Result := FData;
end;

procedure TStringClass.LoadFromStream(AStream: TFileStream);
var
size : longint;
begin
AStream.Read(size,SizeOf(size));
setlength(FData,size div 2);
AStream.Read(PChar(FData)^,size);
end;

procedure TStringClass.SaveToStream(AStream: TFileStream);
var
size : longint;
begin
size := length(FData) * SizeOf(char);
AStream.Write(size,SizeOf(size));
AStream.Write(PChar(FData)^,size);
end;

end.
Das klappt auch soweit ganz gut.
Jetzt moechte ich aber eine generische Liste fuer objekte dieses Generischen Typs definieren. Diese Liste soll auch eine Methode enthalten die ein neues Objekt erstellt und der Liste hinzufuegt. Das Problem das ich habe ist die Deklaration der Klasse:

Delphi-Quellcode:
unit UListTypes;

interface

uses
  Classes, Contnrs, UDataTypes;

type
  TListTypeGeneric<TDataObjectType:TDataTypeGeneric<TDataType>,IDataIO,constructor>=class(TObjectList)
  private
    function GetElement(Index: integer): TDataObjectType;
    procedure SetElement(Index: integer; const Value: TDataObjectType);
  protected
    function GetVString: string;virtual;
  public
    function AddNewElement : TDataObjectType;
    procedure LoadFromStream(AStream:TFileStream);
    procedure SaveToStream(AStream:TFileStream);
    property Element[Index:integer] : TDataObjectType read GetElement write SetElement;
    property VString : string read GetVString;   
  end;


implementation

{ TListTypeGeneric<TDataObjectType> }

function TListTypeGeneric<TDataObjectType>.AddNewElement: TDataObjectType;
begin
Result := TDataObjectType.Create;
Add(TDataObjectType(Result));
end;

function TListTypeGeneric<TDataObjectType>.GetElement(Index: integer): TDataObjectType;
begin
Result := TDataObjectType(Items[Index]);
end;

procedure TListTypeGeneric<TDataObjectType>.LoadFromStream(AStream: TFileStream);
var
Size,x : longint;
begin
AStream.Read(FSize,SizeOf(Size));
for x := 0 to Size-1 do
  AddNewElement.LoadFromStream(AStream);
end;

procedure TListTypeGeneric<TDataObjectType>.SaveToStream(AStream: TFileStream);
var
Size,x : longint;
begin
Size := Count;
AStream.Write(FSize,SizeOf(Size));
for x := 0 to Size-1 do
  Element[0].SaveToStream(AStream);
end;

procedure TListTypeGeneric<TDataObjectType>.SetElement(Index: integer;const Value: TDataObjectType);
begin
Items[Index] := Value;
end;

function TListTypeGeneric<TDataObjectType>.GetVString: string;
var
x : longint;
begin
AStream.Write(FSize,SizeOf(Size));
for x := 0 to Count-1 do
Result := Result + Element[x].VString + ',';
end;

end.
Ich hatte das so verstanden das ich bei Generics ein Interface bereitstellen muss wenn ich Methoden vwerwenden will damit sich der Compiler sicher ist das es diese Methoden gibt. Hab auch den Parameter auf Klasse eingeschraenkt und dem Compiler versichert das es einen Constructor gibt. Wenn ich allerdings das Interface einfueger dann meckert er das das Interface kein 'Create kennt'. Und beim constraint 'class' beschwert er sich das TObject kein 'SaveToStream()' kennt...
Das Dumme ist das sich die IDE manchmal direkt beim compilieren/parsen aufhaengt...

Also wie definiert man das richtig, so das es das macht was ich moechte

Fuer jede Hilfe bin ich dankbar

Cheers,
Klaus

PS: Ich benutze Delphi 10.3.1 (aber das ist nicht auswaehlbar im Threadformular)

Geändert von Catweasel77 ( 5. Mai 2019 um 15:34 Uhr)
  Mit Zitat antworten Zitat