![]() |
Kopie eines Klassenobjekts erstellen
Zu aller erst möchte ich auf diese Seite verweisen auf die ich bei meiner Googlesuche gestoßen bin.
![]() Da habe ich jetzt die Info her, dass man mit Assign() eine Kopie von TPersistent-Objekten erstellen kann, es sei denn man hat eine eigene Klassenimplementierung / ein eigenes TObject. Solche Objekte haben keine Assign-Methodik und man muss sie selber implementieren. Ich konnte in der VCL keinen Code finden der mir eine Art Grundlage gibt, auf die ich aufbauen kann. Könnt ihr mir helfen? Mein Klassenobjekt ist so deklariert
Delphi-Quellcode:
Oder ist es am einfachsten von TPersistent abzuleiten statt von TObject?
TMyObject= class(TObject)
|
AW: Kopie eines Klassenobjekts erstellen
Beispiele sind TFont oder TStringList.
|
AW: Kopie eines Klassenobjekts erstellen
Moin...:P
Delphi-Quellcode:
...fertsch. :P
class function TSEAMToolsJson.ObjectCopy(aValue: TObject): TObject;
var MarshalObj: TJSONMarshal; UnMarshalObj: TJSONUnMarshal; JSONValue: TJSONValue; begin Result := nil; MarshalObj := TJSONMarshal.Create; try UnMarshalObj := TJSONUnMarshal.Create; try JSONValue := MarshalObj.Marshal(aValue); try if Assigned(JSONValue) then Result := UnMarshalObj.Unmarshal(JSONValue); finally JSONValue.Free; end; finally UnMarshalObj.Free; end; finally MarshalObj.Free; end; end; Hinweis: bei Problemen siehe ![]() |
AW: Kopie eines Klassenobjekts erstellen
Und wie performant ist das mit dem JSON hin und her konvertieren?
Es sieht allerdings deutlich aufgeräumter aus als
Delphi-Quellcode:
Sherlock
procedure TCTGNote.Assign(Source: TCTGNote);
begin if Assigned(Source) and (Source is TCTGNote) then begin Self.fID := Source.fID; Self.fTraceID := Source.fTraceID; Self.fEntryDate := Source.fEntryDate; Self.fNote := Source.fNote; Self.fUserName := Source.fUserName; Self.fUserID := Source.fUserID; Self.fNoteType := Source.fNoteType; end; end; |
AW: Kopie eines Klassenobjekts erstellen
Zitat:
|
AW: Kopie eines Klassenobjekts erstellen
Brrr, bloß nich über JSON, das wird doch jede zweite Version erstmal für 1 oder 2 Updates kaputt gemacht...
|
AW: Kopie eines Klassenobjekts erstellen
Wenn überschaubare Anzahl an Feldern nehme eine eigene Methode zum Kopieren.
Vorteil: - am Performantesten - Prüfungen zur Laufzeit möglich - Debugging ist einfach Nachteil: - ggf. viel Quelltext Wenn der Aufwand für viele Felder zu hoch ist, dann nehme einen Ansatz per RTTI (Google: "delphi copy object rtti"). |
AW: Kopie eines Klassenobjekts erstellen
@OP
Wenn man eine eigenes Objekt kopierbar habe will implemtiert man die Methoden Assign und AssignTo selbst. Wenn man ein Objekt von TPersistent ableitet muss man Methoden zum Speichern(als stream/Datei) und Lesen(von Stream/Datei) des Objekts implemtieren. Es ist mit hilfe der sogenannten RTTI und vor allem der Advanced-RTTI Unterstützung aktueller Delphi Versionen möglich eine Objekt-Kopier-Funktion zu schreiben, welche ziemlich viele Arten von einfachen Objekten kopiert. Es gibt dabei natürlich einiges zu bedenken! Wenn Objekte welche ihrerseits Objekte Referenzieren kopiert werden sollen muss geklärt sein ob es sich bei diesen Referenzen um Assoziationen oder Compositionen handelt. Da RTTI nicht preisgibt ob ein Attribut vom Typ Objekt-Referenz durch eine Methode dieses Objekts erzeugt und zerstört wird. Es bedürfte also eines Markers zur Unterscheidung von Assoziation und Composition im Aufbau der Klassen...und das wird bei den Mitgelieferten klassen nicht bereits unterschieden. Kann aber für eigene klassen umgesetzt werden. Klassen die reine Name-Wert-Paare sind lassen sich am leichtesten über RTTI kopieren. Leider bläht RTTI das Kompilat auf! Und man muss manchmal dafür sorgen das RTTI für eigene Klassen global zur Verfügung stehen. Bei Komplexeren klassen muss man evtl. beim kopieren auf zirkuläre referenzen prüfen (siehe -> durchsuchen eines Graphen aka DFS vs BFS) |
AW: Kopie eines Klassenobjekts erstellen
Zitat:
Ist von TPersistent ableiten also gut genug und genau so perfomant wie TObject? Es geht hier um das Erstellen von circa 150 bis 200 Klassenobjekten bei Programmstart. So wie ich das sehe leitet TPersistent am Ende auch wieder nur von TObject ab und fügt 7 neue Prozeduren und Funktionen ein. Komplizierte Objekttypen habe ich nicht. Strings, Integer und eindimensionale Arrays (String, Integer und einfache Enums). |
AW: Kopie eines Klassenobjekts erstellen
Wenn die Klassen, die kopiert werden sollen, so umfangreich und zahlreich werden, kann man auch Code generieren - entweder durch Tools wie DelphiAST, oder man packt die Klassen in ein Projekt, in denen das anhand deren RTTI passiert. Dann hat man die Vorteile von beiden Herangehensweisen.
|
AW: Kopie eines Klassenobjekts erstellen
Verstanden was du da gerade geschrieben hast, habe ich leider nicht :pale:
Stellen 100 Properties denn ein Problem dar? Speicherverbrauch meiner Anwendung mit und ohne Klassenobjekten im Detail mit 0 Klassenobjekten bei Programmstart 9,2 MB mit 70 Klassenobjekten 10,7 MB. |
AW: Kopie eines Klassenobjekts erstellen
Meine Aussage bezog sich auf den Post von QuickAndDirty zuvor
|
AW: Kopie eines Klassenobjekts erstellen
Ich mach es z. B. so:
Delphi-Quellcode:
Anmerkung: Die Methoden BeginUpdate() und EndUpdate() habe ich selbst implementiert weil es sie in in TPersistent nicht gibt. (Delphi 2009)
TtoTreeNodeAttribute = class(TtoCollectionItem)
private FData: TtoData; FName: String; ... protected procedure SetName(Value: String); procedure SetData(Value: TtoData); ... public ... procedure AssignTo(Dest: TPersistent); override; published property Name: String read FName write SetName; property Data: TtoData read FData write SetData; ... end; ... procedure TtoTreeNodeAttribute.AssignTo(Dest: TPersistent); var DestObj: TtoTreeNodeAttribute; begin inherited AssignTo(Dest); if Dest is TtoTreeNodeAttribute then begin DestObj := TtoTreeNodeAttribute(Dest); DestObj.BeginUpdate; try DestObj.FData.Assign(FData); DestObj.FName := FName; ... finally DestObj.EndUpdate; end; end; end; procedure TtoTreeNodeAttribute.SetName(Value: String); begin if (FName <> Value) and (Value <> '') then FName := Value; end; procedure TtoTreeNodeAttribute.SetData(Value: TtoData); begin FData.Assign(Value); end; ... |
AW: Kopie eines Klassenobjekts erstellen
Delphi-Quellcode:
Bei ein paar Properties kein Problem. Bei alles über 50 aufwendig und doppelter Aufwand, wenn irgendwas geändert werden muss. Mal von der Gefahr abgesehen, wenn man vergisst AssignTo ebenfalls zu erweitern wenn man die Klasse erweitert.
DestObj.FData.Assign(FData);
DestObj.FName := FName; |
AW: Kopie eines Klassenobjekts erstellen
Zitat:
|
AW: Kopie eines Klassenobjekts erstellen
Zitat:
Zitat:
Sonst, wenn das besser ist, nehme ich Tigüs Idee ( ![]() Das mit Json lasse ich wegen dem Argument, dass Embarcadero das ja oft kaputt macht., Zitat:
|
AW: Kopie eines Klassenobjekts erstellen
Zitat:
|
AW: Kopie eines Klassenobjekts erstellen
Laut Windows Process Explorer, direkt nach Programmstart wenn alles geladen wurde:
TObject, private bytes 19.704 K, working set 31,644 K TPersistent, private bytes 19.648 K, working set 31.536 K Es gibt sicherlich einen anderen Unterschied irgendwo aber der scheint bei mir noch so klein zu sein, dass man ihn nicht merkt. Die paar Byte sind heute eh egal und auf die kommts auch nicht an bei einer Speicherreservierung von rund 30 MB. Ich habe das jetzt auch mal was genauer gemacht. Ob das richtig ist, weiß ich aber nicht. Ich bin alle Objekte durchgegangen, habe deren Größe mit InstanceSize bestimmt, addiert und am Ende ausgegeben. Für TPersistent bekomme ich 22680, für TObject auch 22680. Es geht mir keineswegs darum ein paar bytes zu sparen. Ich frage mich nur, warum man TObject mit eigenem Assign, was vielleicht sogar noch anfällig ist, nehmen sollte, obwohl TPersistent doch schon alles liefert. |
AW: Kopie eines Klassenobjekts erstellen
Zitat:
Zitat:
|
AW: Kopie eines Klassenobjekts erstellen
Zitat:
Dann deckt sich das ja mit meinem Fund Zitat:
|
AW: Kopie eines Klassenobjekts erstellen
Na, irgendwo in der VMT muss es ja hin. Ja, es geht hier nur um Bytes. Ja, einzelne Bytes, die man an 0010 Händen abzählen kann.
|
AW: Kopie eines Klassenobjekts erstellen
Manchmal wünschte ich mir, dass man heute selbst noch auf Bytes achtet und die nicht verschwendet. Aber jetzt bei all den Gigabytes an Arbeitsspeicher und Unmengen an CPU-Caches interessiert das leider niemanden mehr - mich eingeschlossen. Das würde einfach zuviel Zeit kosten die paar Bytes zu optimieren.
|
AW: Kopie eines Klassenobjekts erstellen
Zitat:
Wenn die RTL aber schon den CPU Cache mit Müll zupflastert, dann kann man sich auch eigene Microoptimierungen an den Hut stecken ;) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:39 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz