Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Objekt kopieren... gibt es was Neues ? (https://www.delphipraxis.net/166592-objekt-kopieren-gibt-es-neues.html)

haentschman 21. Feb 2012 08:02

Objekt kopieren... gibt es was Neues ?
 
Hallo alle...

Ich wollte 2 getrennte Objekte (Original / geändert) um evt. den Ursprungszustand wieder herstellen zu können und das geänderte für die Validitätsprüfung.
Dabei bin ich der Hilfe von TPersistent ausgeliefert worden... :roll:
Zitat:

Mit Assign kopieren Sie die Eigenschaften und andere Attribute eines Objekts aus einem anderen.
Inzwischen habe ich viel gelesen und herausbekommen daß die Implementierung von Assign selbst erfolgen muß. :(

Da die Beiträge alle samt aus den Jahren 2002 - 2008 etwa stammen drängte sich die Frage auf, ob mit den Neuen Delphi´s evt. neue Techniken eingeführt wurden um eine Objektkopie zu realisieren...

Danke für Info´s

Neutral General 21. Feb 2012 08:11

AW: Objekt kopieren... gibt es was Neues ?
 
Naja mit Hilfe der RTTI lässt sich eigentlich immer was machen. Ab Delphi 2010 (?) sollte man auch die Public-Properties auslesen können glaube ich. (Du musst sie nicht mehr extra published machen).

haentschman 21. Feb 2012 08:13

AW: Objekt kopieren... gibt es was Neues ?
 
Danke für die schnelle Antwort... 8-)

Das mit der RTTI habe ich auch gelesen. Nur reichen mir die Public Properties nicht. Ich bräuchte eine vollständige Kopie.

jaenicke 21. Feb 2012 08:16

AW: Objekt kopieren... gibt es was Neues ?
 
Du könntest eventuell die dbExpress-Routinen benutzen, die auch DataSnap zum Marshalling/Unmarshalling verwendet. Ich fürchte aber, dass dir in der Professional die entsprechenden Units fehlen, da DataSnap erst in der Enterprise dabei ist.

Du kannst ja mal schauen, ob du die Units DBXJSON und DBXJSONReflect hast, dann sehen wir ggf. weiter. ;-)

haentschman 21. Feb 2012 08:27

AW: Objekt kopieren... gibt es was Neues ?
 
Liste der Anhänge anzeigen (Anzahl: 1)
...die wären schon mal da.

jaenicke 21. Feb 2012 08:40

AW: Objekt kopieren... gibt es was Neues ?
 
Dann findest du im SVN hier eine passende Demo, das Repository kannst du einfach mit Delphi öffnen:
https://radstudiodemos.svn.sourcefor...rshalUnmarshal (Root wäre https://radstudiodemos.svn.sourcefor...s/RadStudio_XE)
(Außerdem hast du die Demo dann vermutlich auch schon lokal in den Samples.)

Für dich interessant sind die Knöpfe zum Marshalling und Unmarshalling. ;-)

mjustin 21. Feb 2012 09:09

AW: Objekt kopieren... gibt es was Neues ?
 
Zitat:

Zitat von Neutral General (Beitrag 1152071)
Naja mit Hilfe der RTTI lässt sich eigentlich immer was machen. Ab Delphi 2010 (?) sollte man auch die Public-Properties auslesen können glaube ich. (Du musst sie nicht mehr extra published machen).

Auch ein Zugriff auf Variablen mit "private" Sichtbarkeit ist mit Extended RTTI (ab Delphi 2010) möglich

himitsu 21. Feb 2012 09:12

AW: Objekt kopieren... gibt es was Neues ?
 
Selbst "private" Dinge lassen sich mit der neuen RTTI standardmäßig auslesen (ja, es gibt einen Grund, warum die EXEn so groß geworden sind :roll: )
[edit] Da war zwar wer schneller, aber egal. :angle2: [/edit]

Aber beim Kopieren muß man aufpassen, denn vorallen wenn Pointer und Handle im Spiel sind (noch schlimmer, wenn gecastete Pointer und Handle z.B. als Integer vorkommen) oder irgendwelche Indize auf eindeutige externe Strukturen (z.B. die ID einer Hardware- oder Datenbankverbindung), dann kann man ohne Kenntnisse des Aufbaus und der Funktion dieses Objektes eigentlich nichts kopieren, ohne irgendwas kaputtzumachen.

Aus diesem Grund sollte man vorallem vor den Interna (private/protected) eher Abstand nehmen.

mjustin 21. Feb 2012 09:13

AW: Objekt kopieren... gibt es was Neues ?
 
Diese Lösung ist sehr kompakt, erfordert nur Delphi 2010 und keine weiteren Bibliotheken:

http://stackoverflow.com/a/9197330/80901

Sie verwendet die neuen JSON Klassen in Delphi um das Objekt erst zu serialisieren und dann wieder in ein neues zu deserialisieren.

jaenicke 21. Feb 2012 09:21

AW: Objekt kopieren... gibt es was Neues ?
 
Genau die Lösung wird ja in der Demo oben verwendet...

haentschman 21. Feb 2012 09:45

AW: Objekt kopieren... gibt es was Neues ?
 
Sooo...
Hab die Demo mal am laufen. Wenn ich das richtig verstehe zerpfückt Marshall das Object in JSON "Text" incl. Daten. Das Unmarshall setzt aus diesem "Text" ein Object zusammen und gibt es zurück.

Leider bekomme ich beim Unmarshall mit TPerson1 eine Zugriffsverletztung. Die Listen gehen.

Die Richtung stimmt schon mal oder ?

jaenicke 21. Feb 2012 10:04

AW: Objekt kopieren... gibt es was Neues ?
 
Ja, das stimmt so. Bei XE gibt es aber noch einen Fehler, der dazu führt, dass Dezimalzahlen nicht korrekt übertragen werden. Leider wird nämlich der lokale Dezimalseparator benutzt und der stimmt nun einmal in Deutschland mit dem Feldtrennzeichen von JSON überein. Ich glaube daher rührt der Fehler.

Deshalb musst du bei XE vor dem Marshalling/Unmarshalling den Dezimalseparator auf einen Punkt setzen und danach wieder zurück. Bei XE2 ist das behoben.

himitsu 21. Feb 2012 10:09

AW: Objekt kopieren... gibt es was Neues ?
 
Wenn man aber lokal kopiert, dann sollte das doch egal sein? (wenn beim Unmarshallen der selbe "lokale" Separator verwendet wird, wie beim Marshallen)

Schau dir mal den JSON-String an, also ob dort auch alles drin ist, was rein müßte.

haentschman 21. Feb 2012 10:18

AW: Objekt kopieren... gibt es was Neues ?
 
8-) Du traust mir echt zu, daß ich das verstehe ?
Zitat:

{"type":"Person1.TPerson1","id":1,"fields":{"FFirs tName":"aSampleFirst","FLastName":"aSampleLast","F WeightLb":160,"FHeightIn":70,5,"FDateOfBirth":2226 1,"FAddresses":[["addHome","aSampleHomeStreet","aSampleHomeCity","a SampleHomeState","aSampleHomeZip"],["addWork","aSampleWorkStreet","aSampleWorkCity","a SampleWorkState","aSampleWorkZip"]],"FPhones":[["aSampleMobileNumber","phMobile"],["aSampleWorkNumber","phWork"],["aSampleHomeNumber","phHome"]]}}
Zitat:

den Dezimalseparator auf einen Punkt setzen
... vom System ?

himitsu 21. Feb 2012 10:29

AW: Objekt kopieren... gibt es was Neues ?
 
Code:
{
  "type": "Person1.TPerson1",
  "id": 1,
  "fields": {
    "FFirstName": "aSampleFirst",
    "FLastName": "aSampleLast",
    "FWeightLb": 160,
    "FHeightIn": 70,
    5,
    "FDateOfBirth": 22261,
    "FAddresses": [
      [
        "addHome",
        "aSampleHomeStreet",
        "aSampleHomeCity",
        "aSampleHomeState",
        "aSampleHomeZip"
      ],
      [
        "addWork",
        "aSampleWorkStreet",
        "aSampleWorkCity",
        "aSampleWorkState",
        "aSampleWorkZip"
      ]
    ],
    "FPhones": [
      [
        "aSampleMobileNumber",
        "phMobile"
      ],
      [
        "aSampleWorkNumber",
        "phWork"
      ],
      [
        "aSampleHomeNumber",
        "phHome"
      ]
    ]
  }
}
[...] = ein Array, bzw. eine Liste
{...} = ein Objekt
x:y = ein Parameter (Name:Wert)

Nur mit dieser namenlosen
Delphi-Quellcode:
5,
kann ich nicht viel anfangen.

Ich weiß jetzt nicht wie das Objekt aussieht (hab hier in keine Anhänge reingesehn), aber Listen scheinen schon drin zu sein. (k.A. ob auch alles richtig ist)

Dezimalzahlen sind hier nicht enthalten, also sollte es damit keine Probleme geben, oder soll das Eine eine 70,5 sein?

haentschman 21. Feb 2012 10:42

AW: Objekt kopieren... gibt es was Neues ?
 
Zitat:

oder soll das Eine eine 70,5 sein?
...ja, die "Höhe" der Person :lol:

in der MainUnit(Form.Create) waren Kommentare bezüglich der Testung alternativer Dezimalseperatoren. Dort habe ich den Dezimalseperator auf "." umgestellt und im OnDestroy wieder zurück. Damit geht auch TPerson1.

Jetzt muß ich mal schauen was ich alles wo benötige. (TTypeFactory etc.) Am besten ich mache mir mal ein Testprogramm und gehe Euch dann auf die Nerven... 8-)

Nachtrag:
Zitat:

Dort habe ich den Dezimalseperator auf "." umgestellt
...mit Ctrl-Klick komme ich zur Deklaration in SysUtils. Heißt das, daß für die Zeit der Dezimalseperator Systemweit umgestellt ist ?
PS: ist der auf einem deutschen System nicht normal sowieso der "." :gruebel:

Bummi 21. Feb 2012 10:43

AW: Objekt kopieren... gibt es was Neues ?
 
unter XE bekomme ich

"Exception der Klasse EInsufficientRtti mit der Meldung 'Unzureichende RTTI zur Unterstützung dieser Operation verfügbar'"

bei :
Delphi-Quellcode:
  With Button2.Clone do
    begin
      left := left + 100;
      top := top + 100;
    end;

haentschman 21. Feb 2012 10:48

AW: Objekt kopieren... gibt es was Neues ?
 
...bei der gleichen Demo ? Hast du die aktuelle Version aus dem Repository ?

himitsu 21. Feb 2012 10:50

AW: Objekt kopieren... gibt es was Neues ?
 
Nicht systemweit (Windows), sondern nur programmweit (in deinem Programm).

PS: Beim Button (allem ab TComponent, wenn ordentlich programmiert), kannst du auch TStream verwenden.
Delphi-Referenz durchsuchenTStream.ReadComponent und Co.

haentschman 21. Feb 2012 10:51

AW: Objekt kopieren... gibt es was Neues ?
 
...ja dann ist es gut. 8-)

himitsu 21. Feb 2012 10:55

AW: Objekt kopieren... gibt es was Neues ?
 
Zitat:

Zitat von himitsu (Beitrag 1152100)
PS: Beim Button (allem ab TComponent, wenn ordentlich programmiert), kannst du auch TStream verwenden.
Delphi-Referenz durchsuchenTStream.ReadComponent und Co.

PS: Hatte noch was nacheditiert.

Zum Auslesen müßtest du aber die Komponente erstemal erstellen und dann mit den StreamDaten befüllen.
Vollen Klassennamen merken und dann kann man über die RTTI die Typdeklaration der Klasse suchen und darüber erstellen lassen.
Ich glaub daheim hab ich noch irgendwo etwas dafür-

haentschman 21. Feb 2012 10:57

AW: Objekt kopieren... gibt es was Neues ?
 
Danke erstmal... 8-)

Bei meinen Anforderungen handelt es sich ausschließlich um eigene "Daten"-Objekte.

Nachtrag:
Ich hatte diverse Beiträge auf Seite 1 übersehen. Vor allem der Link in Beitrag 9 http://www.delphipraxis.net/1152083-post9.html und der weiterführende Link sind sehr aufschlußreich.

Danke an alle. Wenn das, so wie verlautet, auch mit generischen Listen im Objekt funktioniert, wäre das "Muster" gut geeignet für die CodeLib...

Nachtrag Lösung:
habe jetzt nach folgendem Muster umgestellt...
Delphi-Quellcode:
.....
uses
  DBXJSON, DBXJSONReflect;
.....
 
function DeepCopy(aValue: TObject): TObject;
var
  MarshalObj: TJSONMarshal;
  UnMarshalObj: TJSONUnMarshal;
  JSONValue: TJSONValue;
begin
  Result:= nil;
  MarshalObj := TJSONMarshal.Create;
  UnMarshalObj := TJSONUnMarshal.Create;
  try
    JSONValue := MarshalObj.Marshal(aValue);
    try
      if Assigned(JSONValue) then
        Result:= UnMarshalObj.Unmarshal(JSONValue);
    finally
      JSONValue.Free;
    end;
  finally
    MarshalObj.Free;
    UnMarshalObj.Free;
  end;
end;
Verwendung...
Delphi-Quellcode:
.....
var
  MyObject1,
  MyObject2: TMyObject;
begin
  //Regular object construction
  MyObject1:= TMyObject.Create;

  //Deep copying an object
  MyObject2:= TMyObject(DeepCopy(MyObject1));

  try
    //Do something here

  finally
    MyObject1.Free;
    MyObject2.Free;
  end;
end;
Die Verwendung als ClassHelper ist auch sehr interessant. (Siehe Link)

Erste Tests sind gut. Wollen wir dann mal schauen wie das mit "Unterobjekten" und generischen Listen funktioniert.

Danke an alle...:hi:

stahli 21. Feb 2012 11:59

AW: Objekt kopieren... gibt es was Neues ?
 
Ich habe (unter XE) eine eigene Funktion geschrieben, die bestimmte Objekteigenschaften direkt an ein anderes Objekt zuweist.

Die betreffenden Eigenschaften sind mit einem Attribut gekennzeichnet.
Die Objekte (Tod) haben eine gemeinsame Basis. Die Ableitungen (Todl) verwalten zusätzlich eine Liste von Tod-Objekten.

Falls jemand eine Anregung daraus übernehmen will, hier der Quelltext:

Delphi-Quellcode:
  TodCourt = class(TodCustomStahliSport)
    ...
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function IsFree: Boolean;
    [AttrOd] // <- Kennzeichnung zum Kopieren
    property Number: Integer read get_Number write set_Number;
    [AttrOd]
    property CourtType: TCourtType read get_CourtType write set_CourtType;
    [AttrOd]
    property Activate: Boolean read get_Activate write set_Activate;
    [AttrOd]
    property Game: TodGame read get_Game write set_Game;
    [AttrOd]
    property PositionValues: String read get_PositionValues write set_PositionValues;
  published
  end;

//

procedure TodProp.AssignFromTo(odFrom, odTo: Tod);
var
  ContextFrom: TRttiContext;
  ContextTo: TRttiContext;
  RttiTypeFrom: TRttiType;
  RttiTypeTo: TRttiType;
  PropInfoFrom: TRttiProperty;
  PropInfoTo: TRttiProperty;
  FFrom: Boolean;
  FTo: Boolean;
  AttrFrom: TCustomAttribute;
  AttrTo: TCustomAttribute;
  ValueFrom: TValue;
  ValueTo: TValue;
  _oFrom, _oTo: TObject;
  _odFrom, _odTo: Tod;
  odlFrom: Todl;
  odlTo: Todl;
begin
  if (not Assigned(odFrom)) or (not Assigned(odTo)) then
    Exit;

  ContextFrom := TRttiContext.Create;
  RttiTypeFrom := ContextFrom.GetType(odFrom.ClassType);

  ContextTo := TRttiContext.Create;
  RttiTypeTo := ContextTo.GetType(odTo.ClassType);

  if (Assigned(RttiTypeFrom)) and (Assigned(RttiTypeTo)) then
    begin
      for PropInfoFrom in RttiTypeFrom.GetProperties do
        begin
          FFrom := False;
          for AttrFrom in PropInfoFrom.GetAttributes do
            begin
              if AttrFrom is AttrOd then
                FFrom := True;
            end;
          if FFrom then
            begin
              for PropInfoTo in RttiTypeTo.GetProperties do
                begin
                  FTo := False;
                  for AttrTo in PropInfoTo.GetAttributes do
                    begin
                      if AttrTo is AttrOd then
                        FTo := True;
                    end;
                  if FTo then
                    begin
                      if PropInfoFrom.PropertyType = PropInfoTo.PropertyType then
                        begin
                          ValueFrom := PropInfoFrom.GetValue(odFrom);
                          if PropInfoTo.IsWritable then
                            begin
                              PropInfoTo.SetValue(odTo, ValueFrom);
                            end
                          else
                            begin
                              _oFrom := ValueFrom.AsObject;
                              if _oFrom is Tod then
                                _odFrom := (_oFrom as Tod)
                              else
                                _odFrom := nil;
                              ValueTo := PropInfoTo.GetValue(odFrom);
                              _oTo := ValueTo.AsObject;
                              if _oTo is Tod then
                                _odTo := (_oTo as Tod)
                              else
                                _odTo := nil;
                              if Assigned(_odTo) then
                                begin
                                  if Assigned(_odFrom) then
                                    _odTo.Assign(odFrom)
                                  else
                                    _odTo.Clear;
                                end;
                            end;
                        end;
                    end;
                end;
            end;
        end;
    end;

  ContextFrom.Free;
  ContextTo.Free;

  if (odFrom is Todl) and (odTo is Todl) then
    begin
      odlFrom := (odFrom as Todl);
      odlTo := (odTo as Todl);
      // outputdebugstring(pchar('a:' + inttostr(odlFrom.Items.Count)));
      // outputdebugstring(pchar('b:' + inttostr(odlTo.Items.Count)));
      odlTo.Items.Assign(odlFrom.Items);
      // outputdebugstring(pchar('c:' + inttostr(odlFrom.Items.Count)));
      // outputdebugstring(pchar('d:' + inttostr(odlTo.Items.Count)));
    end;
end;

@haentschman

Mit generischen Klassen sollte eine solche Serialisierung auch funktionieren. Man kann lediglich nicht eine generische Klasse von einer anderen ableiten und diese Ableitung später nachvollziehen (sofern ich das so richtig zusammenfasse).


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:33 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz