Предотвращение редактирования элементов списка после назначения списку - PullRequest
0 голосов
/ 17 июня 2020

Итак, я пытаюсь составить список, состоящий из разных версий локальной переменной, которая постоянно меняется каждые l oop. Однако после выполнения l oop все значения будут такими же, как и самые последние, потому что они обновляются вместе с заданным значением, а не остаются на том же уровне, когда я их назначал. Вероятно, есть довольно простое решение этой проблемы, но мне не удалось найти его методом проб и ошибок. Вот небольшой пример того, что я пытаюсь сделать:

List<Item> itemList = new List<Item>();
Item itemA = new Item;

while(repeating condition)
{
    itemList.Add(itemA)
    // *itemA changes*
}

Итак, я хочу, чтобы itemList имел новую запись каждые l oop, которая не изменяется вместе с itemA после добавления.

Ответы [ 4 ]

1 голос
/ 17 июня 2020

Поскольку itemA является ссылочным типом, ваш список содержит несколько копий ссылки на Item. В комментарии, где написано \\ itemA changes, код, скорее всего, изменяет только свойства Item, на которые ссылается itemA:

List<Item> itemList = new List<Item>();
var itemA = new Item { SomeProperty = someValue };

while(repeating condition)
{
    itemList.Add(itemA)

    // itemA changes (but not really - we only change the instance it refers to)
    itemA.SomeProperty = newValue;
}

Итак, все, что на самом деле происходит, - это объект, который itemA относится к изменению, но itemA технически остается прежним - он по-прежнему указывает на тот же объект в памяти.

Чтобы решить проблему, нам нужно переназначить itemA новому instance of Item, а не просто изменяет экземпляр, на который он ссылается. В приведенном вами примере кода (который немного скуден - вы должны включить код, который «изменяет» itemA), он может выглядеть так:

List<Item> itemList = new List<Item>();
Item itemA = new Item { SomeProperty = someValue };

while(repeating condition)
{
    itemList.Add(itemA)

    // Now itemA *does* change - we set it to refer to a *new* instance of Item
    itemA = new Item { SomeProperty = newValue };
}
1 голос
/ 17 июня 2020

Поскольку вы на самом деле никогда не изменяете (для нового объекта) объект, на который указывает ваш itemA в памяти, все, что вы получаете, это список, например, 100 записей, которые все просто указывают на один и тот же единственный экземпляр ItemA в памяти

В терминах, с которыми вы, возможно, более знакомы, ваши new ItemA() данные подобны текстовому файлу на диске, а itemA - это ярлык для него. Вызов list.Add(itemA) (или связывание другой переменной, например var itemA2 = itemA) просто создает еще один ярлык для того же файла, а не копирует файл в другой файл.

Если вы дважды щелкните ярлык itemA, чтобы открыть файл в блокноте, отредактировать содержимое, сохранить его, закрыть, а затем дважды щелкнуть ярлык itemA2, то вы не удивитесь, увидев, что блокнот открывается с файл с вашими изменениями

Это то, что C# делает, когда вы создаете объекты

var myShortcut1 = new RealDataSomewhere();
var myShortcut2 = myShortcut1; //not a copy, another shortcut to the same realdata

var myArrayOfShortcuts = new [] { myShortcut1, myShortcut1, myShortcut1, myShortcut1, myShortcut1}; //every array index is also a shortcut

//at this point there is still only one RealDataSomewhere object in memory and now 7 shortcuts to it

Либо клонируйте свой itemA до / после того, как вы что-то с ним сделаете, добавив клоду в список , или создавайте новый itemA на каждом проходе l oop. Что из этого вы на самом деле делаете, зависит от того, что остальная часть кода (мы не можем видеть) делает с элементом A

клонирование,

0 голосов
/ 17 июня 2020

Class являются ссылочным типом, как и List. C# Список основных ссылок экземпляров классов в List. Если вы измените переменную, элемент списка, который ссылается на этот элемент, будет ссылаться на этот измененный элемент. Поэтому, если ваша переменная изменяется, и вы не хотите отражать это изменение в своем списке, вы должны сделать глубокую копию своей переменной, а затем добавить ее в список. вы можете сделать это следующим образом: здесь .

0 голосов
/ 17 июня 2020

То, что вы делаете, - это сохраняете ссылку на itemA, так что list в конечном итоге представляет собой набор переменных, которые все указывают на одни и те же данные. Что вам нужно сделать, так это скопировать объект и сохранить копию.

Попробуйте заменить itemList.Add(itemA) на itemList.Add(itemA.Clone()).

Вам придется написать метод Clone() самостоятельно, а реализация зависит от вас. Это может быть конструктор, принимающий элемент в качестве параметра и копирующий его значения, или метод, возвращающий клон объекта, для которого он был вызван.

См. Ответ Кая Джарда, где можно найти ссылку на более подробное обсуждение клонирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...