Laden...

Instanz wird durch Zuweisung nicht kopiert [Kopierkonstruktor, ICloneable, ...]

Erstellt von baensch vor 13 Jahren Letzter Beitrag vor 13 Jahren 6.837 Views
B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren
Instanz wird durch Zuweisung nicht kopiert [Kopierkonstruktor, ICloneable, ...]

Da bei einem solchen befehl


myClass class = new myClass();
myClass y = class;

die beiden Instanzen "eine Instanz" sind wäre meine idee gewesen einen Konstruktor zu schreiben der alle variablen kopiert das würde dann so aussehen.

Konstruktor


public myClass(myClass oldClass)
{
    this.x = oldClass.x;
    .....
}

Aufruf


myClass y = new myClass(class);

warum funktioniert das trotzdem nicht (also wenn ich class.x ändere ändert sich auch y.x mit und umgekehrt)


while(!asleep)
{
    sheep++;
}

1.002 Beiträge seit 2007
vor 13 Jahren

Hallo baensch,

du hast einen sogenannten Kopierkonstruktor implementiert. Wenn das von dir beschriebene Verhalten auftritt, ist das Feld oder die Eigenschaft x ein Referenztyp und kein Wertetyp – dessen Wert würde übernommen werden und würde sich bei einer Änderung nicht auf die andere Instanz auswirken. So teilen sich die Instanzen den Referenztyp – du hast in diesem Fall nur eine shallow copy, eine flache Kopie, erstellt.
Wenn du nicht-geteilte Referenztypen in den Instanzen verwenden willst, musst du eine deep copy, eine tiefe Kopie, durchführen.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren

Oh das hätte ich auch bemerken können. 🤔

Gibt es da auch eine Einfachere Lösung oder ist die einzige nur wertetypen zu kopieren?


while(!asleep)
{
    sheep++;
}

Z
403 Beiträge seit 2007
vor 13 Jahren

Hallo baensch,

schau dir dazu auch mal das IClonable Interface an:

ICloneable-Schnittstelle

ggf. hier im Forum danach suchen.

André

849 Beiträge seit 2006
vor 13 Jahren

Hallo,

wenn ich eine wirkliche Kopie eines Objectes brauche, serialisiere ich es in einen MemoryStream und deserialisiere es wieder. Bisher imho die wirksamste Methode (wenn auch nicht die performanteste).

grüße

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo zusammen,

wenn man Objekte kopieren möchte, ist das meistens ein Hinweis darauf, dass mit dem Design was nicht stimmt. Siehe Kopie ohne ICloneable.

herbivore

916 Beiträge seit 2008
vor 13 Jahren

wenn ich eine wirkliche Kopie eines Objectes brauche, serialisiere ich es in einen MemoryStream und deserialisiere es wieder

Das ist m.E. die wohl schlechteste Lösung. Das IClonable Interface ist doch genau für das Kopieren von Objekten da, und das Objekt selber sollte schon wissen welche referenz Member es neu instanziieren muss!

Again what learned...

B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren

@herbivore

wenn man Objekte kopieren möchte, ist das meistens ein Hinweis darauf, dass mit dem Design was nicht stimmt.

Ich habe eine ObservableCollection mit einer selbst geschriebenen Klasse. Diese Klasse besteht aus einer ObservableCollection, die die Geometrie der Instanz beschreibt und eine Variable, die die Qualität der Instanz beschreibt.

Am Anfag ist das StartObjekt und das EndObjekt in der ObservableCollection. Ich berechne den Weg vom Start zum EndObjekt und füge die fehlenden Zwischenschritte ein.
(z.B. Anfang: StartObjekt.Qualität = 0; EndObjekt.Qualität = 3;
Ende(nach meiner Bearbeitung sollte die Collection so aussehen): StarObjekt.Qualität=0; Objekt1.Qualität = 1; Objekt2.Qualität = 2; EndObjekt.Qualität = 3;)

Hättest du vielleicht einen besseren Vorschlag für mein Problem, denn ich sehe keinen anderen Ausweg.


while(!asleep)
{
    sheep++;
}

B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren

@unconnencted

serialisiere ich es in einen MemoryStream und deserialisiere es wieder

kannst du mir sagen wie das konkret aussieht?
meinst du etwa mit XMLSerializer?


while(!asleep)
{
    sheep++;
}

1.665 Beiträge seit 2006
vor 13 Jahren

Er meint wahrscheinlich den BinaryFormatter (.Serialize()).

B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren

danke einmal ich werde die ICloneable Schnittstelle verwenden


while(!asleep)
{
    sheep++;
}

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo baensch,

Hättest du vielleicht einen besseren Vorschlag für mein Problem, denn ich sehe keinen anderen Ausweg.

ich sehe in deiner Beschreibung keine Stelle, an der Objekte kopiert werden müssen.

herbivore

B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren

ich sehe in deiner Beschreibung keine Stelle, an der Objekte kopiert werden müssen

Doch das Objekt1 hat z.B.: genau die selbe Geometrie wie das StartObjekt.
Somit kopiere ich das StartObjekt und ändere nur die Qualität.

Was ist an Clonen so schlecht zieht man daraus irgend welche Nachteile?


while(!asleep)
{
    sheep++;
}

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo baensch,

was am Kopieren von Objekten schlecht ist, habe ich ja in dem verlinkten Thread beschrieben.

Wobei es in deinem Fall so ist, dass du das zu kopierende Objekt quasi nur als Vorlage für ein echt neues Objekt verwendest. Also das Ganze ein bisschen in Richtung Prototyp (Entwurfsmuster) geht. So ein Vorgehen kann dann schon Sinn machen.

herbivore

B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren

Ok vielen dank


while(!asleep)
{
    sheep++;
}

S
443 Beiträge seit 2008
vor 13 Jahren

Kann sein dass ich zu spät dran bin, aber:
soweit ich das verstanden habe sind in deinem "StartObjekt" Koordinaten eines Punktes drin.
Weiters ist auch die Qualität drin (was auch immer Qualität bedeutet)
Dein Problem ist dass Du einen Punkt (StartObjekt) mit verschiedenen Qualitäten brauchst.
was hältst Du davon wenn Qualität ein eigenes Object wird, initialisiert mit:

Qualität qualität = new Qualität(3);

und dass als Schlüssel in einem Dictionary benützt

dictionary.Add(qualität, startObjekt);

somit hättest Du jedem Punkt eine Qualität verpasst ohne dass Du Dein StartObjekt verändern muss (somit musst du es nicht mehr kopieren)

mbg
Rossegger Robert
mehr fragen mehr wissen

Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen

B
baensch Themenstarter:in
135 Beiträge seit 2010
vor 13 Jahren

Danke spike24,
leider sind die Collection und die Qualität nur die beiden wichtigsten Variablen meiner Klasse somit ist die lösung mit einem Dictionary nicht möglich.


while(!asleep)
{
    sheep++;
}

849 Beiträge seit 2006
vor 13 Jahren

Hmm, also als Abschluss vllt. noch einmal als Erklärung warum ich mich beim (nicht performance kritischen) clonen nicht auf IClonable verlasse..

a. bei großen Daten Objecten sagen wir 20 Propertys aufwärts wird die Clone Methode unübersichtlich, und wenn dann noch collections dabei kommen irgendwann unwartbar.

b. Ich arbeite mit mehreren Entwicklern zusammen, die auch an den erstellten Objecten arbeiten.. und wenns dann mal wieder schnell gehen muss, wird meistens :IClonable und Clone() übersehen, und einfach ein Property hinzugefügt, das dann beim clonen fehlt. (Ich will mich selber da nicht ausschliessen).

Klar wenns um performance geht, ist das natürlich grottig. Aber es läuft stabil und hat sich bewährt.

und wie JunkyXL schon sagte benutze ich tatsächlich den Binary Formatter bzw. den DataContractSerializer (Silverlight)

Grüße

5.657 Beiträge seit 2006
vor 13 Jahren

a. bei großen Daten Objecten sagen wir 20 Propertys aufwärts wird die Clone Methode unübersichtlich, und wenn dann noch collections dabei kommen irgendwann unwartbar.

Für diese Fälle gibt es doch die MemberwiseClone-Methode.

Weeks of programming can save you hours of planning

849 Beiträge seit 2006
vor 13 Jahren

Kleiner ausschnitt aus der doku zu Memberwise Clone

Die MemberwiseClone-Methode erstellt eine flache Kopie, indem ein neues Objekt erstellt wird und anschließend die nicht statischen Felder des aktuellen Objekts in das neue Objekt kopiert werden. Wenn ein Feld ein Werttyp ist, wird das Feld bitweise kopiert. Wenn es sich bei dem Feld um einen Verweistyp handelt, wird nicht das Objekt, auf das verwiesen wird, sondern der Verweis kopiert. Daher verweisen das ursprüngliche Objekt und der Klon auf dasselbe Objekt.

So eine flache Kopie kann man wirklich in den seltensten Fällen gebrauchen.

T
381 Beiträge seit 2009
vor 13 Jahren

Ich weiß, auch nicht die Beste Lösung, aber damals hab ich so etwas mal per Reflection gelößt. Ich hatte ein Objekt mit vielen Properties in einer Bibliothek und konnte es nicht ändern, wollte aber eine Kopie ohne jede Property einzeln kopieren zu müssen, da hat sie die Reflection (auch um an private member zu kommen) bewährt. Das konnte ich auch soweit steuern, dass ich einige nicht kopierbare Teile die auch ein BinaryFormatter nicht nimmt (Sockets und so...) manuell auslassen konnte.

Also im groben, mit Reflection ein Objekt auseinander und die Werte in nem neuen Objekt setzten. Alles von außen ohne das zu kopierende Objekt zu ändern.

Ansonsten kann man noch an bestimmten Stellen überlegen Structs zu benutzten. Hab mir dein Beispiel jetzt nicht genau genug angesehen um zu beurteilen ob es dir hilft.