Wie ich schon schrieb halte ich den Ansatz, die über die Properties zu iterieren und diese jeweils zu kopieren, - wenn überhaupt mit vertretbarem Aufwand umsetzbar - für ziemlich aufwändig, fehleranfällig und schlecht wartbar. Immerhin muss bei jedem neuen Property geprüft werden, ob sich das so einfach kopieren lässt und das auch sachlich korrekt durchgeführt wird. Nicht immer enthalten die Properties Strings oder numerische Werte. Klasseninstanzen, Interfaces oder auch Arrays werden so nur als Referenzen und nicht inhaltlich kopiert. Das ist in der Regel bei Arrays und oft bei Klassen gar nicht gewollt. Solche Fälle müssten jeweils gesondert behandelt werden, was bei der
RTTI-Lösung den Aufwand beträchtlich steigert.
Den empfohlenen Ansatz hat Frank schon mit
TPersistent.Assign und seinem Pendant
TPersistent.AssignTo angesprochen. Dieses Verfahren ist schon so alt wie Delphi, wird allgemein verstanden und hat sich bei korrekter Anwendung als stabil erwiesen.
Man kann sich die Implementierung in den simplen Fällen (Strings und numerische Werte) vereinfachen, wenn man die einzelnen Felder hinter den Properties einen record verlagert, der mit einfacher Zuweisung kopiert werden kann. Das deckt die ursprüngliche Absicht zur Vereinfachung der Wartbarkeit bereits ab. Da in dem beschriebenen Fall offenbar mit Interfaces gearbeitet wird, sind sowieso schon Getter und Setter vorhanden, die dann auf die Record-Felder umgeleitet werden. Eine mögliche Implementierung der
TPersistent.Assign Ableitung sähe dann, unter der Annahme dass
TProduct direkt von
TPersistent abgeleitet ist, in etwa so aus:
Delphi-Quellcode:
procedure TProduct.Assign(Source: TPersistent);
begin
if Source is TProduct then begin
FData := TProduct(Source).FData;
end
else
inherited;
end;
Bei dem
Assign mit einem
IProduct als Source wird es etwas komplexer und es bieten sich je nach Gegebenheiten mehrere Lösungsmöglichkeiten an:
- Man erweitert IProduct um eine entsprechende Methode, die dann in allen Implementierungen entsprechend gefüllt werden muss.
- Man deklariert ein separates Interface für das Assign, das man dan über Supports abfragt.
- Wenn sichergestellt ist, dass alle Implementationen von IProduct auf TPersistent aufbauen: Assign(Source as TPersistent);