2016-07-19 9 views
-1

Ich verwende diese Routine, um einige Koordinaten in einen Container zu laden, sie zu zeichnen, hineinzuzoomen und diese Art von Aufgaben. Dann, bei einem Klick, tendiere ich dazu, Reset alles auf den ursprünglichen oder ursprünglichen Zustand. Dazu nehme ich eine Kopie der Initiale und spiele mit der Kopie. Aber wenn ich auf die Reset-Taste klicke, zerstöre ich die Kopie, nimm eine neue Kopie der Initiale und bearbeite sie. Und so weiter.Warum ändert sich der ursprüngliche Wert, wenn ich eine Kopie davon verarbeite?

Aus irgendeinem Grund ändert sich der ursprüngliche Container, wenn ich die Kopie ändere. Könnte jemand herausfinden, was ich falsch mache?

Um lade ich die Daten zuerst und eine Kopie nehmen:

//   CoordPoint is a simple xy point 
public List<CoordPoint> MyLoadedCoords { get { return myLoadedCoords; } set { myLoadedCoords = value; }} 
public List<CoordPoint> MyDisplayedCoords { get { return myDisplayedCoords; } set { myDisplayedCoords = value }} 

private List<CoordPoint> myLoadedCoords; 
private List<CoordPoint> myDisplayedCoords; 

//.. 

public void LoadData() 
    { 
     // load points from file 
     MyLoadedCoords = File.ReadLines("C:\\...\\Samples.txt") 

     // get a copy of original coords 
     MyDisplayedCoords = MyLoadedCoords.ToList(); 
    } 

Beachten Sie, dass MyLoadedCoords existiert nicht, wo im Code erwarten hier (und in der Reset-Funktion, nach unten). Dann bearbeite ich die Kopie MyDisplayedCoords mehreren Stellen ähnlich wie diese:

public void UpdateDisplayPosition() 
{ 
    for (var i = 0; i < MyDisplayedCoords.Count; i++) 
    { 
     MyDisplayedCoords[i].X += XCoordOffset; //some processed values 
     MyDisplayedCoords[i].Y += YCoordOffset; //some processed values 
    } 
} 

Reset-Taste Ich tue dies:

public void ResetZoom() 
{ 
    MyDisplayedCoords = MyLoadedCoords.ToList(); // I set break point here 
    AdjustInitialDisplayPosition(); 
    DrawImage(); 
} 

ResetZoom() nicht tut, was zu erwarten ist, wenn ich debuggen und brechen auf MyDisplayedCoords = MyLoadedCoords; ich sehe, dass MyLoadedCoords enthält exakt die gleichen Werte/Objekte wie MyDisplayedCoords

EDIT:

I umgesetzt IClonable und "overrided" die Clone() Funktion in meiner Klasse, aber es hat NICHT Arbeit:

public class CoordPoint : ICloneable 
{ 
    // .. 

    public object Clone() 
    { 
     return new CoordPoint {X = X, Y = Y, Z = Z, Color = Color}; 
    } 
} 

jedoch mit aus den IClonable, das "Kopieren" arbeitet als Klonen H.B antwortete:

MyDisplayedCoords = MyLoadedCoords.Select(c => new CoordPoint { X = c.X, Y = c.Y, Z = c.Z, Color = c.Color }).ToList(); 
+0

Sie eine Kopie nicht bekommen, sind Sie tatsächlich Arbeiten an einer neuen Liste mit den gleichen Datenzeigern. Um dies zu beheben, müssen Sie entweder Klonen verwenden, das verschachtelte Referenztypen nicht unterstützt, oder Ihren eigenen Klon implementieren. – Phaeze

+0

@FirstStep, CoordPoint, ist es Klasse oder Struktur? Denn wenn es sich um eine Klasse handelt, erstellt .ToList() eine neue Liste, die dieselben Referenzen enthält. –

+0

@ArtavazdBalayan ist eine Klasse. Interessant, ich wusste das nicht, also wenn es eine Struktur wäre, hätte es funktionieren können? –

Antwort

5

MyDisplayedCoords = MyLoadedCoords nichts kopiert, weist er eine erneute Wenn das gleiche Objekt mit einer Eigenschaft verknüpft ist, zeigen nun beide Eigenschaften auf dasselbe Objekt.

eine Liste kopieren Sie auf der Linq Methoden verwenden könnten (die immer eine neue Liste zurück):

MyDisplayedCoords = MyLoadedCoords.ToList(); 

Um tiefe Kopie Sie so etwas tun könnte, dann die Instanzen in den Listen werden auch anders:

MyDisplayedCoords = MyLoadedCoords.Select(c => 
             new CoordPoint { X = c.X, Y = c.Y }).ToList(); 
+0

Ich mache das 'MyDisplayedCoords = MyLoadedCoords.ToList()' zunächst, also sollte es eine Kopie nicht zuweisen? –

+0

Ja, aber dein 'ResetZoom' macht das nicht und von diesem Punkt an hast du das gleiche Objekt, vielleicht rufst du das irgendwo an? –

+0

Dann müssen Sie, wie von Vishnu vorgeschlagen, tief kopieren. –

2

auf HB Antwort, schafft

hinzufügen

ToList ein neues List Objekt, aber die Objekte in der Liste s sind nur Referenzen auf die gleichen object, es sei denn, sie sind unveränderliche Objekte (Zeichenfolge zum Beispiel oder primitive Typen).

Ihr ursprüngliches Objekt List ist in diesem Fall nicht betroffen (Hinzufügen neuer Objekte/Entfernungen usw.), aber Änderungen an Objekten spiegeln sich in beiden wieder. Weil sie dasselbe Objekt referenzieren.

Sie können entweder H.B's Antwort folgen, um neue als neue Objekte zu kopieren oder den folgenden Prozess zu befolgen, der sauberer und korrekter ist.

Gerät ICloneable Schnittstelle in CoordPoint Klasse. überschreiben Sie die Clone Methode und rufen Sie sie während des Kopierens auf. Ein bisschen lang Methode, aber so wird Ihr Code Linq richtig aussehen.

public class CoordPoint : ICloneable 
{ 
    //rest of your code here 

    public object Clone() 
    { 
    return new CoordPoint 
       { 
        X= X, 
        Y = Y 
       }; 
    } 
} 

Dann wird Ihr Linq Code wird,

MyDisplayedCoords = MyLoadedCoords.Select(c => (CoordPoint)c.Clone()).ToList(); 
+1

"es sei denn, sie sind unveränderliche Objekte" sollte wahrscheinlich "wenn sie keine Werttypen sind" sein. – adv12

+0

Hallo, also wie könnte ich das beheben? –

+0

@FirstStep Bitte überprüfen Sie, ob meine Lösung für Sie funktioniert –

0

Wenn Sie ‚Kopieren‘ Liste Objekt, das Sie eine neue Liste bekommen, aber die Elemente in dieser Liste verweisen alle noch auf die gleichen Elemente Als der erste.

Der einfachste Weg, um dieses Problem zu erhalten, ist die ICloneable Schnittstelle, hier eine kurze Probe:

public class MyObject : ICloneable 
{ 
    public string Property { get; set; } 
    public object Clone() 
    { 
     return this.MemberwiseClone(); 
    } 
} 

Verbrauch:

var list = new List<MyObject>() { new MyObject { Property = "FirstObject" } }; 
var clonedList = list.Select(x => x.Clone());