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)