0

So I'm trying to make a list that consist of different versions of a local variable that keeps changing every loop. However, after the loop is done all the values are the same as the most recent one because they update along with the given value as opposed to staying the same value when I assigned them. There is probably a pretty simple solution to this problem but I have not been able to find it through trial and error. Here a little example of what I am trying to do:

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

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

So I want itemList to have a new entry every loop that does not change along with itemA after being added.

Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • Move `Item itemA = new Item;` inside the loop. – LarsTech Jun 17 '20 at 20:04
  • Please show the code where `itemA` changes. That is where the problem most likely is, because `Item` is a reference type. You're probably doing something like `itemA.SomeProperty = newValue;`, which doesn't actually change `itemA`, it only changes the object to which it refers. If you do `itemA == new Item();`, **then** it's actually changing. – Rufus L Jun 17 '20 at 20:11
  • Have you tried adding a breakpoint to the code and then step though? This will give you a better understanding on what's going wrong. Basically, your variable isn't changing between each loop of the `while` statement. I think stepping through might help you here. – Chris Walsh Jun 18 '20 at 00:03

4 Answers4

1

Because you never actually change out (for a whole new object) the object that your itemA is pointing to in memory, all you end up with is a list of e.g. 100 entries that are all just pointing to the same sole instance of ItemA in memory

In terms you might be more familiar with, your new ItemA() data is like having a text file on disk somewhere and itemA is a shortcut to it. Calling list.Add(itemA) (or associating another variable like var itemA2 = itemA) is merely creating another shortcut to the same file, it is not copying the file to another file.

If you double click your itemA shortcut to open the file in notepad, edit the contents, save it, close it, then doubleclick itemA2 shortcut then you wouldnt be surprised to see that notepad opens showing a file that has your changes

This is what C# does when you make objects

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

Either clone your itemA before/after you do things to it, adding the clode to the list, or make a new itemA on every pass of the loop. Which of these you actually do depends on what the rest of the code (we can't see) does with itemA

There is a long discussion about cloning here including several handy suggestions for deep cloning,

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
1

Since itemA is a reference type, your list contains a bunch of copies of a reference to an Item. In the comment where it says \\ itemA changes, the code is most likely only changing properties of the Item that itemA refers to:

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

So all that's really happening is that the object that itemA refers to is changing, but itemA is technically still the same - it's still pointing to the same object in memory.

To resolve the issue, we need to reassign itemA to a new instance of Item rather than just modifying the instance it refers to. In the sample code you provided (which is a little sparse - you should include the code that "changes" itemA) it might look like:

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 };
}
Rufus L
  • 36,127
  • 5
  • 30
  • 43
0

What you are doing is saving a reference to itemA, so list ends up being a bunch of variables that all point to the same data. What you need to do is copy the object and save the copy.

Try replacing itemList.Add(itemA) with itemList.Add(itemA.Clone()).

You will have to write the Clone() method yourself, and the implementation is up to you. It could be a constructor that takes an item as a parameter and copies it's values or a method that returns a clone of the object it was called on.

See Caius Jard's answer for a link to more discussion on cloning.

Jacob Huckins
  • 368
  • 2
  • 15
0

Class are reference type as List does. C# List strores refrences of class instances in List. If you change the variable the List item which is references to that item will refer to that changed item. So if your variable changes and you don't want to refelect that change to your List you must make deep copy of your variable and then added to List. you can do this y the way introduced here.

Hamed Sanaei
  • 121
  • 13