2016-07-19 7 views
-1

Я использую эту процедуру для загрузки некоторых координат в контейнер, рисования их, увеличения их и подобных задач. Затем при нажатии кнопки я склонен к Сбросить все в исходное или исходное состояние. Для этого я беру копию оригинала и играю с копией. Но на кнопке Reset нажмите, я уничтожу копию, возьму новую копию исходного и обработаю ее. И так далее.Почему первоначальное значение изменяется, если я обрабатываю его копию?

По какой-то причине первоначальный контейнер изменяется при изменении копии. Может ли кто-нибудь определить, что я делаю неправильно?

Для того, я загружаю данные первого и взять копию:

//   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(); 
    } 

Обратите внимание, что MyLoadedCoords существует не где в коде ожидать здесь (и в функции сброса, вниз). Затем я обрабатываю Копируйте MyDisplayedCoords несколько мест, похожее на это:

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 
    } 
} 

Кнопка сброса Я делаю это:

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

ResetZoom() не делать то, что, как ожидается, когда я отладки и разорвать на MyDisplayedCoords = MyLoadedCoords; я вижу, что MyLoadedCoords содержит те же самые значения/объекты как MyDisplayedCoords

РЕДАКТИРОВАТЬ:

Я реализовал IClonable и «перекрытая» функцию Clone() в моем классе, но это было НЕ работы:

public class CoordPoint : ICloneable 
{ 
    // .. 

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

Однако, с из в IClonable, это «копирование» работает как клонирование, как H.B ответил:

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

Вы не получаете копию, вы на самом деле работая над новым списком со всеми теми же указателями данных. Чтобы решить эту проблему, вам нужно либо использовать Clone, который не поддерживает вложенные ссылочные типы, а реализовать собственный глубокий клон. – Phaeze

+0

@FirstStep, CoordPoint, это класс или структура? Потому что если это класс, .ToList() создаст новый список, который будет содержать те же ссылки. –

+0

@ArtavazdBalayan это класс. Интересно, что я этого не знал, поэтому, если бы это была структура, это могло бы сработать? –

ответ

5

MyDisplayedCoords = MyLoadedCoords ничего не копирует, он назначает повторное к тому же объекту относится свойство, теперь оба свойства указывают на один и тот же объект.

Чтобы скопировать список, который вы могли бы использовать на методы Linq (которые всегда возвращают новый список):

MyDisplayedCoords = MyLoadedCoords.ToList(); 

Для глубокой копии вы могли бы сделать что-то подобное, то экземпляры в списках будут также быть разными:

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

Я делаю это 'MyDisplayedCoords = MyLoadedCoords.ToList()' изначально, поэтому он должен назначить копию нет? –

+0

Да, но ваш 'ResetZoom' не делает этого, и с этого момента у вас будет один и тот же объект, может быть, вы это называете? –

+0

Затем вам нужно сделать глубокую копию, как предложила Вишну. –

2

Чтобы добавить в ответ HB, в

ToList создает новый объект List, но объекты внутри списка s - это просто ссылки на те же object, если они не являются неизменяемыми объектами (например, строки или примитивные типы).

Ваш оригинальный List объект не будет затронут в этом случае (добавление новых объектов/удаление и т. Д.), Но изменения в объектах отразятся на обоих. Потому что они ссылаются на один и тот же объект.

Вы можете либо следовать за ответом H.B, чтобы копировать новые как новые объекты, либо следовать следующему процессу, который является более чистым и правильным.

Внесите ICloneable интерфейс в CoordPoint класс. переопределите метод Clone и вызовите его во время копирования. Немного длинный метод, но так будет выглядеть ваш код Linq.

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

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

Тогда ваш Linq код будет,

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

", если они не являются неизменяемыми объектами " вероятно, должны быть «если только они не являются типами значений». – adv12

+0

Привет, так как я могу это исправить? –

+0

@FirstStep, пожалуйста, проверьте, работает ли мое решение для вас –

0

Когда вы «копировать» список вашего объекта вы получаете новый список, но элементы в этом списке все еще указывает на те же самые пункты как первый.

Самый простой способ, чтобы обойти эту проблему, является интерфейс ICloneable, вот короткий пример:

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

Использование:

var list = new List<MyObject>() { new MyObject { Property = "FirstObject" } }; 
var clonedList = list.Select(x => x.Clone()); 
Смежные вопросы