@Bjoerk:
Ohne Generics macht das ganze nicht so viel Sinn.
Und Clear kannst du auch problemlos in einen Record einbauen...
Ein komplettes Beispiel mit einigen der Möglichkeiten findest du hier.
Ein Vorteil ist, dass du dich nicht selbst um die Pointer kümmern musst. Du hast einfach immer eine Referenz, also einen impliziten Pointer, und fertig. Für das Zuweisen der Werte kannst du, wenn du von TPersistent ableitest, Assign oder AssignTo überschreiben (oder du implementierst es als normale Methode neu, wenn du von TObject ableitest).
Vorteil des Überschreibens von AssignTo:
Es wird schon vorher geprüft, ob nil übergeben wurde und ggf. ein qualifizierter Fehler ausgelöst und wenn die falsche Klasse zugewiesen wird, brauchst du nur inherited aufrufen und es kommt auch ein qualifizierter Fehler.
Du musst keine Properties verwenden, du kannst es also auch genauso schreiben wie du es bei Records hattest (die heute aber auch Properties kennen), aber die haben den Vorteil, dass die privaten Felder nicht direkt erreichbar sind und du ggf. leicht Setter oder Getter einbauen kannst.
Ein wenig mehr Quelltext ist es in der Klasse oft schon, aber dafür ist die Verwendung sehr viel einfacher. In der Praxis wird die Anzahl der Verwendungen sehr viel höher sein als die einmalige Implementierung der Klasse, so dass es sehr viel sinnvoller ist die Verwendung zu vereinfachen als bei der Implementierung der Klasse selbst zu sparen.
Delphi-Quellcode:
unit Unit15;
interface
uses
System.Generics.Collections, System.Classes,
Vcl.Dialogs;
procedure Test;
implementation
type
TTest =
class(TPersistent)
private
var
FString1:
String;
FString2:
String;
FDouble1: Double;
protected
procedure AssignTo(Dest: TPersistent);
override;
public
constructor Create(
const AString1:
string;
const AString2:
string = '
';
const ADouble1: Double = 0.0);
overload;
constructor Create(
const ACloneSource: TTest);
overload;
property String1:
String read FString1
write FString1;
property Double1: Double
read FDouble1
write FDouble1;
property String2:
String read FString2
write FString2;
end;
TMyList =
class(TObjectList<TTest>)
public
end;
procedure Test;
var
Test: TMyList;
Current: TTest;
begin
Test := TMyList.Create(True);
try
Test.Add(TTest.Create('
Test 1'));
Test.Add(TTest.Create('
Test 2'));
Test.Add(TTest.Create('
Hallo'));
Current := TTest.Create('
Clone Source');
try
Test.Add(TTest.Create(Current));
// Neues Objekt aus Current erzeugen
finally
Current.Free;
end;
for Current
in Test
do
ShowMessage(Current.String1);
// alle ausgeben
// zuweisen
Current := TTest.Create;
try
Current.Assign(Test[2]);
ShowMessage(Current.String1);
// Hallo
finally
Current.Free;
end;
finally
Test.Free;
// Die Objekte in der Liste werden durch das True für OwnsObjects im Konstruktor freigegeben
end;
end;
{ TTest }
procedure TTest.AssignTo(Dest: TPersistent);
var
Destination: TTest;
begin
if Dest
is TTest
then
begin
Destination := TTest(Dest);
Destination.String1 := FString1;
Destination.String2 := FString2;
Destination.Double1 := FDouble1;
end
else
inherited;
end;
constructor TTest.Create(
const AString1:
string;
const AString2:
string = '
';
const ADouble1: Double = 0.0);
begin
FString1 := AString1;
FString2 := AString2;
FDouble1 := ADouble1;
end;
constructor TTest.Create(
const ACloneSource: TTest);
begin
Assign(ACloneSource);
end;
end.