4

I have a List (in C#) of an object (class that I created). I am able to use the list but the problem is that I only created (instantiated I think is the proper term) one of my object class and I keeping adding it to the list even though the properties of that object change with iterations of the code. I would like to be able to add hardcoded objects to my list and not the reference object.

Here is what I am currently doing:

public class SaveData
{
    public double save_property1;
    public double save_property2;    
}

in the application

SaveData newSaveData = new SaveData();
List<SaveData> newSaveDataList = new List<SaveData>;

if ( some condition)
{
    newSaveData.save_property1 = x
}

if (some condition 2) 
{
    newSaveData.save_property2 = y 
    newSaveDataList.Add(SaveData);  // 
}

Since X and Y change over the iterations, I want the SaveDate object I add to the list NOT to change with each iteration (so I can keep a history of the Data objects), i.e. hardcode and not use as reference.

Servy
  • 202,030
  • 26
  • 332
  • 449
AbeeCrombie
  • 597
  • 1
  • 5
  • 22
  • 1
    Why have you tagged (and mentioned in the title) an `ArrayList` when you're instead using a strongly typed `List` (which i would also prefer)? – Tim Schmelter Oct 26 '12 at 13:44
  • Not quite clear on what you're trying to do. You might want to able to clone your objects?! – Mithrandir Oct 26 '12 at 13:46

4 Answers4

6

You can't do that, you will need to create a new object each time you want to add to the list or you will just keep modifying the old one.

Remember that when you add a reference type to the list, you are just putting the reference into the list and not the object being referred to. This means that if you always push the same instance, all "items" in the list are really the same item. Consider:

newSaveData                        1000
+-----------+                      +--------------------+
| 1000      |--------------------->| save_property1     |
+-----------+                      | save_property2     | 
                                   +--------------------+
newSaveDataList                               ^
+-----------+                                 |
| 1000      |---------------------------------+
+-----------+                                 |
| 1000      |---------------------------------+
+-----------+                                 |
| 1000      |---------------------------------+
+-----------+                                 |
| 1000      |---------------------------------+
+-----------+

So instead, you need to create a new instance of the object for each add to the list, so that they are all distinct objects that can vary:

while (yourLoopCondition)
{
    // each item you want to add, create a new instance.
    newSaveData = new SaveData();
    if (someCondition1)
    {
        newSaveData.save_property1 = x
    }

    if (someCondition2) 
    {
        newSaveData.save_property2 = y 
        newSaveDataList.Add(newSaveData);  
    }
}

The above assumes that each object is distinct and not an "object in flight" across multiple iterations of the loop.

Now, if you have one main object and you're just trying to put a "snapshot" of that object in the list, you could do this with some sort of cloning method or "copy constructor" of sorts:

public class SaveData
{
    public double save_property1;
    public double save_property2;

    public SaveData(SaveData other)
    {
        save_property1 = other.save_proerty1;
        save_property2 = other.save_property2;
    }
}

Then if you want to put a snapshot on the list of an object in flight, you could do:

newSaveDataList.Add(new SaveData(newSaveData));

Or, you could use a struct instead which is a value type and thus would place a copy in the list, but struct has a lot of interesting quirks and one should consider those very carefully before using them. I have a post on this topic here

James Michael Hare
  • 37,767
  • 9
  • 73
  • 83
  • thanks James. you got my problem, that i just keep modifying the old object. I will check out your post. Otherwise I was thinking of creating a class with a SaveData collection/list of SaveData objects and then add new objects with the properties of the 1 SaveData object I created. Would that work? – AbeeCrombie Oct 26 '12 at 13:54
  • @user1449677: as long as each object added to the list is distinct (separate reference, or a value type). – James Michael Hare Oct 26 '12 at 14:00
  • Stucts do the trick so far! Thanks. The article is a bit over my head but I am going through it. This program is fairly simple so I think it will do. – AbeeCrombie Oct 26 '12 at 14:12
  • @user1449677: fair enough, main thing to remember about `struct` is it's almost opposite of reference type. If you assign it to another variable it makes a copy so modifying one *doesn't* modify the other. Also when you pass into a function it copies, so modifying in a function won't modify original. And because they are copies, if the struct is big (> 16 bytes) it tends to get less efficient than a reference type... – James Michael Hare Oct 26 '12 at 14:20
  • Even better James, that snapshot trick works as well, and then I dont have to worry about the stuct problems. Thanks so much! (I cant really add the while/for loop as I am coding inside someone elses code and it complicates things too much) – AbeeCrombie Oct 26 '12 at 14:41
  • @user1449677 anytime! Glad I could help. – James Michael Hare Oct 26 '12 at 14:42
2

I think I understand what you are asking. You are finding yourself with a list of references to the same object which reflects the latest state (values of x and y) rather than a set of references to historical values.

The reason for this is that you are adding references to the same object to your list, and that you are changing this one referenced object, rather than creating new objects each time. You should simply be able to create a new SaveData on each iteration to solve your problem.

var history = new List<SaveData>();
while (someCondition)
{
    var sd = new SaveData(...);

    if (someOtherCondition)
    {
        sd.saveProperty1 = someValue;
    }

    ...

    history.Add(sd);
}
Paul Ruane
  • 37,459
  • 12
  • 63
  • 82
0

Your example code I think is not quite right, because you have

SaveData.save_property1 = x;

Where I think you mean

newSaveData.save_property1 = x;

Try this, which shows how to create several SaveData object with different field values, and to add the objects to your list.

List<SaveData> newSaveDataList = new List<SaveData>();
for (int index = 0; index < 10; index++)
{
    SaveData saveData = new SaveData();
    saveData.save_property1 = (double)index;
    saveData.save_property2 = (double)index * 2;
    newSaveDataList.Add(saveData);
}

foreach (SaveData saveData in newSaveDataList)
{
    Console.WriteLine(saveData.save_property1);
    Console.WriteLine(saveData.save_property2);
}
Polyfun
  • 9,479
  • 4
  • 31
  • 39
0

For the thing to work, you need to create a new object and copy all the fields from previous object into the new one, then change the desired property. The copy operation is something you need to implement yourself. This operation is called 'cloning'.

Take a look at these two questions:

Cloning objects in C#
How do you do a deep copy an object in .Net (C# specifically)?

You can also user Object.MemberwiseClone if you don't need a deep copy:

public class SaveData : ICloneable
{
    public double save_property1;
    public double save_property2;    

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

and then:

if (some condition 2) 
{
    SaveData copySaveData = newSaveData.Clone();
    copySaveData.save_property2 = y;
    newSaveDataList.Add(copySaveData);
}

or the other way:

if (some condition 2) 
{
    newSaveData.save_property2 = y;
    newSaveDataList.Add(newSaveData);
    newSaveData = newSaveData.Clone();
    // from now on all the new changes will happen to a new object, not the one in the list.
}
Community
  • 1
  • 1
Mohammad Dehghan
  • 17,853
  • 3
  • 55
  • 72