Deep Copy

  • C#

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Switcherlapp97.

    Hallo,

    Für meinen RubiksCubeSolver würde ich gerne aus dem verdrehten Würfel-Objekt ein neues Objekt erstellen. Das neu erstellte Objekt soll komplett unabhängig von der alten Instanz sein, damit ich beim Lösen nur die neu erzeuge Instanz drehe und nicht den Original Cube. Ich habe schon gegoogelt und bin dann schließlich auf den Begriff Deep Copy gestoßen. Ein paar Codeschnipsel, die ich bei meiner Google-Suche gefunden habe, habe ich dann auch gleich getestet, doch leider ohne Erfolg. Die meisten Ergebnisse habe ich zum Serialisieren gefunden. Bei mir ist das nicht möglich, da meine Klasse nicht serialisierbar gemacht werden kann. Habt ihr eine Idee, wie ich das anstellen könnte?

    Gruß
    Switcherlapp97
    RubiksCubeSolver


    Jetzt im Showroom
    Da du deine Eigene Klasse ja kennst, kannst du doch einfach eine DeepCopy-Funktion implementieren, oder? Du musst halt dafür sorgen, dass für jede Eigenschaft ein neues Objekt erzeugt wird, nicht dass bloß die Referenz auf das alte kopiert wird.
    ICloneable sollte nicht mehr verwendet werden, da es von Microsoft als Veraltet gekennzeichnet wurde. Grund ist, dass Clone eben keinen Aufschluss auf die Art des Klonens gibt und das Interface auch nicht generisch ist.
    @Artentus
    Also muss ich alle Eigenschaften einzeln neu erzeugen? Gibt es dafür eigentlich keine .NET-Framework-Methode, die einem die Arbeit erspart?
    RubiksCubeSolver


    Jetzt im Showroom
    Ich weiß nicht wie die "empfohlene" Vorgehensweise ist, aber bei uns hat es sich etabliert, einen zusätzlichen Konstruktor bereitzustellen, der als einzigen Parameter ein Objekt der eigenen Klasse annimmt und daraus dann die Eigenschaften dupliziert (sog. "Copy-Konstruktor").
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.
    Habe mich auch schon oft darüber geärgert, dass es da nichts gibt. Sieht jedoch ganz so aus als könne man da nicht viel machen. Manche serialisieren das Objekt und deserialisieren dieses anschließend. Jedoch bin ich nicht wirklich ein Fan davon. Drückt auch irre auf die Performance.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    eine allgemeingültige DeepCopy-Methode ist einfach prinzipiell unmöglich, jedenfalls für Klassen, die Innereien enthalten, die Referenz-Typen sind.
    Der Begriff "Kopie" ist bei Referenztypen einfach nicht eindeutig:
    ist mit "Kopie" gemeint, einen neuen Verweis zu erstellen, der halt aufs selbe Objekt verweist?
    oder ist damit gemeint, einen Verweis zu erstellen, der auf ein neues, kopiertes Objekt verweist?

    Beides kann sinnvoll sein, je in verschiedenen Szenarien.

    Bei Werttypen sieht das anders aus, da ist der Begriff "Kopie" eindeutig: es wird immer ein neues Objekt erstellt.
    Deshalb ist auch die Protected Function MemberwiseClone() As Object, die einfach die Byte-Folge von sich selbst kopiert, für WertTyp-Innereien sinnvoll. Enthaltene Wert-Typen sind damit korrekt kopiert, während enthaltene Verweis-Typen ggfs. einer Nach-Bearbeitung bedürfen.
    Wer also die ICloneable-Schnittstelle implementieren will - dem kann MemberwiseClone ggfs. etwas von der Arbeit abnehmen - aber meist eben nicht alles.
    Hi
    außerdem kann es ja sein, dass der Konstruktor außerhalb der aktuellen Instanz Änderungen vornimmt; das könnte solch ein Konstruktor gar nicht berücksichtigen.
    @ErfinderDesRades: Prinzipiell werden auch Klassen korrekt kopiert, da ja quasi der vom "Typ dargestellte Wert" kopiert wird, also die Daten der Klasse oder des Wertetyps. In einem Wertetyp kann aber auch ein Referenztyp gespeichert werden. In so einem Fall wird dann eben die Referenz, die ja als Wert auch auf dem Stapel läge, kopiert. D.h. auch bei Wertetypen muss man vorsichtig sein.

    Ich würd's ebenfalls über IClonable lösen oder bei kleinen Objekten mit Strukturen. Man kann übrigens auch eine geeignete Struktur entwickeln, indem man den Cube über Indices verwaltet und nur speichert, wo die Indices sind. Insgesamt hat man ja dann bspw. 3x3x3-1 Unterwürfel, d.h. man könnte 5 Bits (entspricht 32 möglichen Werten) dazu verwenden, um den Würfel eindeutig zuzuordnen. Wenn man die Möglichkeiten weiter reduziert, kann man ggf. sogar weniger Fälle haben, aber so müsste man halt 3x3x3-1-1 5-Bit-Werte speichern (der letzte ergibt sich über den Ausschluss der restlichen) und das wären dann 125 Bits und das könnte man in 2 Longs darstellen.
    Diese Struktur könnte man dann halt wunderbar lösen.

    Ggf. könnte man auch einfach die Schritte mit minimaler Schrittzahl, die benötigt werden, um den Würfel in Ausgangsstellung zu drehen, identifizieren (über eine Ganzzahl) und dann damit eben den Status des Würfels festhalten.

    Gruß
    ~blaze~

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „~blaze~“ ()

    ~blaze~ schrieb:

    In einem Wertetyp kann aber auch ein Referenztyp gespeichert werden. In so einem Fall ... muss man vorsichtig sein.
    Ja, das meinte ich ja: Nicht ob die zu klonende Klasse Wert- oder Ref-Typ ist, sondern wes Typs ihre "Innereien" sind ist das Problem.
    Eine Class, deren Innereien nur aus Werttypen bestehen, ist mit MemberwiseClone() korrekt geklont. (Eine entsprechende Structure klont sich ja automatisch, einfach bei Zuweisung)
    Übrigens bei String als Innerei gibts die besonderheit, dass String-Innereien auch so korrekt mit-geklont werden, denn String ist eine immutable Klasse.

    Wir könnens auch mal am Beispiel machen: Angenommen, jmd. will ein Label klonen, was auf einem Panel liegt. Nu hat Label eine Parent-Property, und die verweist aufs Panel. Worauf soll nun der Label-Klon verweisen? Auf ein neues Panel, oder auf das bestehende?
    Natürlich aufs bestehende, denn wenn auf ein neues Panel, dann muss man auch alle weiteren Controls des Panels mit-klonen, und wird am Ende die ganze Anwendung geklont haben.
    Aber die Funktionalität des Label-Klons wird vmtl. sehr überraschend sein: Ein Label funzt ja nur deshalb, wie wirs kennen, weils in der Controls-Auflistung seines Parents enthalten ist. Das ist unser Label-Klon aber nicht - oder sollemer ihn da mit rein-tun?
    also ist glaub klar, dass zB Controls inclonable sind. Verweistypen können halt (müssen aber nicht) Abhängigkeiten ohne Ende aufweisen, und zwar wörtlich: "ohne Ende".

    Klonen und Serialisieren ist übrigens ungefähr dasselbe. Ein Objekt ist serialisierbar, wenn für jede Innerei (und für die Innereien der Innerei) definiert ist, ob und wie ein Abbild im AusgabeStream erstellt wird.
    Eben nicht unbedingt: Man stelle sich ein Szenario ähnlich Folgendem vor:

    VB.NET-Quellcode

    1. Public Class TestClass
    2. Private Shared _instances As Integer
    3. Private _instance As Integer
    4. Public Sub New()
    5. Me.New(False)
    6. End Sub
    7. Public Sub New(createMuted As Boolean)
    8. If createMuted Then
    9. _instance = 0
    10. Else
    11. _instance = Threading.Interlocked.Increment(_instances)
    12. End If
    13. End Sub
    14. End Class

    Sicher, die Daten sind gültig, usw. aber das vorgesehene Inkrementieren funktioniert nicht zwangsweise.
    Prinzipiell ist ein Objekt serialisierbar, wenn ein SerializableAttribute-Attribut auf den Typ der Instanz gesetzt ist. Die Serializierung selbst kann das Objekt definieren (siehe ISerializable-Schnittstelle), aber es kann keine Garantie gegeben werden, dass die Serialisierung rein auf Datenbasis korrekt abläuft. Bei ISerializable und dem Attribut ist das dann eben schon der Fall. Es kann ja auch sein, dass ein Datum lediglich ein Schlüssel ist, der ohne zugehörigem Wert keinen Sinn ergibt. Würden dann nur die Schlüssel serialisiert, aber die Werte nicht, wäre die Integrität der Daten nicht gewährleistet.

    Gruß
    ~blaze~
    Hallo,

    Danke für eure hilfreichen Antworten :). Ich habe es jetzt manuell gelöst und für jede Klasse die in dem Würfelobjekt vorhanden ist eine Clone-Methode mit MemberwiseClone geschrieben um auch die Propertys klonen zu können. Es funktioniert nun alles so, wie es soll. Ich hätte es übirgens ehrlich gesagt nicht gedacht, dass das so viel Arbeit ist eine unabhängige Kopie eines Objektes zu erstellen :D

    Vielen Dank
    Switcherlapp97
    RubiksCubeSolver


    Jetzt im Showroom