seltsames Ergebnis in Clone ()

8

Ich lerne C # Deep Copy und Shallow Copy. Hier wird nach dem Ändern von demo_obj1 der Objektwert geändert, aber die Liste wird nicht aktualisiert, aber in demo_obj2 wird der Objektwert geändert und auch der Listenwert aktualisiert. Wer weiß, was hier passiert? Danke

Visual Studio 2017

.Net Framework 4.6

%Vor%

Ausgabe:

%Vor%     
QweRty 17.07.2017, 10:32
quelle

4 Antworten

6

Es hat nichts mit Klonen zu tun, es ist das Problem der Referenzen.

Sie haben zwei Objekte obj1 und obj2 erstellt und in eine Liste eingefügt.
Jetzt iterieren Sie durch die Sammlung, geben sie aus und erhalten die erwarteten Ergebnisse.

Referenzen sind die folgenden jetzt:

%Vor%

Später haben Sie nach obj1 = obj2 eine Referenz von obj2 zu obj1 zugewiesen. Du änderst nicht seinen Wert oder kopierst dein Objekt, du kopierst einfach die Referenz und lässt sie auf ein anderes Objekt zeigen Also, beide zeigen jetzt auf das gleiche Objekt Liste enthält die gleichen zwei Verweise auf verschiedene Objekte.

%Vor%

Dann macht obj2.Value = 200 seinen Wert tatsächlich auf 200:

%Vor%

Wenn Sie jetzt obj1 und obj2 UIDs und Werte ausgeben, geben Sie den Wert des gleichen Objekts (Demo_obj2) aus.

%Vor%

Wenn Sie jedoch versuchen, die Auflistung zu durchlaufen, erhalten Sie Demo_obj1 und Demo_obj2 gemäß der Verweistabelle erneut.

%Vor%     
Yeldar Kurmangaliyev 17.07.2017, 10:42
quelle
5

Ich denke also, es gibt ein paar Punkte, die Sie aus dieser Frage verstehen müssen.

Erstens gibt dir die clone() -Methode in Bezug auf deine tatsächliche Frage tatsächlich 2 Objekte. Beide beginnen mit dem Wert 100 und werden zu einer Liste hinzugefügt. Beachten Sie, dass diese Liste auf die Objekte verweist, die in obj1 und obj2 enthalten sind und nicht die Referenzen verwenden, die Sie bereits erstellt haben.

Dann machst du das:

%Vor%

Das bedeutet, dass du deine Referenz obj1 auf obj2 aktualisierst, so dass nun beide auf dasselbe Objekt zeigen. Sie können dies sehen, wenn Sie sich anmelden und 200 zweimal sehen. Beachten Sie, dass Sie die Zeiger in Ihrer Liste nicht aktualisiert haben, da es sich um völlig verschiedene Zeiger handelt.

Schließlich, wenn Sie Ihr zweites Protokoll ausführen, sehen Sie mithilfe der Zeiger in der Liste das ursprüngliche obj1 mit dem Wert 100 und das zweite obj2 , das Sie aktualisiert haben, mit dem Wert 200 .

Das Interessante hier ist, dass es sich nicht wirklich um ein sehr gutes Beispiel für einen tiefen Klon handelt, weil Sie primitive Werte verwenden, die sowieso nur kopiert werden. Um ein besseres Ergebnis zu erzielen, möchten Sie wahrscheinlich einige Werte innerhalb eines Objekts umbrechen:

%Vor%

Wenn Sie jetzt einen Balken erstellen und einen flachen Klon von Foo erstellen, würde er immer noch den gleichen Bar verwenden. Also:

%Vor%

Hier müssen Sie in Deep Cloning gehen, damit jede Foo Instanz eine andere Referenz als eine eindeutige Bar verwendet.

    
Ian 17.07.2017 10:40
quelle
3

Sie haben die Variable obj1 als Instanz in obj2 festgelegt. Der ursprüngliche Wert von obj1 ist weiterhin in der Liste vorhanden. In der Zeile, in der Sie obj1 = obj2; eingeben, wird die Variable obj1 auf obj2 gesetzt. Es ersetzt nicht die Werte der Instanz, die zuvor in obj1 gespeichert wurde. Aus diesem Grund sehen Sie die Ausgaben, die Sie beschreiben.

    
Skintkingle 17.07.2017 10:38
quelle
3

Vergessen Sie MemberwiseClone , es ist ein Ablenkungsmanöver hier.

Ihr Problem ist hier:

%Vor%
  1. Variablen sind Platzhalter für Werte .
  2. Der Wert, der in einer referenzierten Variablen gespeichert wird, ist die "Adresse", an der das Objekt, auf das verwiesen wird, im Speicher "lebt".
  3. Variablen werden standardmäßig nach Wert in C # kopiert.

Das bedeutet also, dass obj1 = obj2; obj1.Value = 200; Folgendes tut:

  1. Erhalten Sie den in obj2 gespeicherten Wert (die Adresse, an der die Instanz { "Demo_obj2"; 100 } lebt.
  2. Kopieren Sie diesen Wert in die Variable obj1 . Der Wert obj1 ist jetzt die Adresse, an der dieselbe Instanz { "Demo_obj2"; 100 } lebt; Sowohl obj1 als auch obj2 zeigen auf dasselbe Objekt .
  3. Ändern Sie Value des Objekts, auf das von obj1 (oder obj2 ) verwiesen wird, auf 200 : das Ergebnis ist die Instanz { "Demo_obj2"; 200 } .
  4. Die von { "Demo_obj1"; 100 } zuvor referenzierte Instanz obj1 wird von keiner Ihrer beiden Variablen obj1 oder obj2 mehr referenziert, aber die Instanz wird noch gespeichert ( Sie haben sie nicht berührt! <) / em>) in der Liste und erreichbar über objList[0] .

Verstehen Sie jetzt, warum Sie das Verhalten erhalten, das Sie sehen?

    
InBetween 17.07.2017 10:44
quelle

Tags und Links