Search code examples
c#ilist

Modifying data member in loop of IList modifies other of elements of IList


I'm very confused about this problem and not sure how to even title this question.

I've created an IList of one of my classes and then used .Add() to populate the IList. Once the IList is populated I need to iterate through the IList for a trivial check of some values and then set one of the data members of each element to 0.00.

The issue is that setting the data member of one element is also setting the same data member of the next elements. Here is an example of the code:

public class MyClass
{
    private int _Id;
    private string _ModelName;
    private double _Price;

    public int Id
    {
        get { return _Id; }
        set { _Id = value; }
    }

    public string ModelName
    {
        get { return _ModelName; }
        set { _ModelName= value; }
    }

    public double Price
    {
        get { return _Price; }
        set { _Price = value; }
    }
}

I am using MyClass like this:

IList<MyClass> MyClasses = new List<MyClass>();

MyClasses.Add( new MyClass { Id = 1, ModelName = "Model1", Price = 119310.05 });
MyClasses.Add( new MyClass { Id = 2, ModelName = "Model1", Price = 119310.05 });
MyClasses.Add( new MyClass { Id = 3, ModelName = "Model1", Price = 119310.05 });
MyClasses.Add( new MyClass { Id = 4, ModelName = "Model1", Price = 119310.05 });
MyClasses.Add( new MyClass { Id = 5, ModelName = "Model2", Price = 19810.32 });
MyClasses.Add( new MyClass { Id = 6, ModelName = "Model2", Price = 19810.32 });
MyClasses.Add( new MyClass { Id = 7, ModelName = "Model2", Price = 19810.32 });

foreach( MyClass myclass in MyClasses )
{
    ... do something ...

    myclass.Price = 0.00;

    ... do something ...
}

Ok, the above code is an extremely simple representation of my actual code. What is happening is that when I set myclass.Price = 0.00; in the foreach loop all of the Price data members with matching ModelName are also getting changed to 0.00. So, in the foreach loop when I set the element with Id = 1 to Price = 0.00 I am immediately seeing this in the IList:

MyClasses.Add( new MyClass { Id = 1, ModelName = "Model1", Price = 0.00 });
MyClasses.Add( new MyClass { Id = 2, ModelName = "Model1", Price = 0.00 });
MyClasses.Add( new MyClass { Id = 3, ModelName = "Model1", Price = 0.00 });
MyClasses.Add( new MyClass { Id = 4, ModelName = "Model1", Price = 0.00 });
MyClasses.Add( new MyClass { Id = 5, ModelName = "Model2", Price = 19810.32 });
MyClasses.Add( new MyClass { Id = 6, ModelName = "Model2", Price = 19810.32 });
MyClasses.Add( new MyClass { Id = 7, ModelName = "Model2", Price = 19810.32 });

I feel like this is a totally stupid question to be asking and I will probably end up finding an equally stupid reason for it happening. I've used F11 to step into every line of code involved and don't see anyplace where Price is getting set in other elements. For that matter, MyClass is completely braindead to the existence of it being contained in an IList.

It seems like this is being caused in the loop itself. I've also tried this approach with the same behavior:

for (int p = 0; p < MyClasses.Count; p++ )
{
    ... do something ...

    myclass[p].Price = 0.00;

    ... do something ...
}

I've added a watch:

MyClasses[p].Price
MyClasses[p + 1].Price
MyClasses[p + 2].Price
MyClasses[p + 3].Price
MyClasses[p + 4].Price

Stepping through the loop shows that when MyClasses[p].Price is set to 0.00 all of the other elements' Price member get set to 0.00.

Is there any possible explanation for this behavior other than there being something causing this in my class? Possibly something to do with an IList?


Solution

  • The most obvious answer to your question is that you are actually copying the same reference to a single instance of MyClass for each unique ModelName value, so your list simply has that same instance in it multiple times. But without a proper concise-but-complete code example, it's impossible to say for sure.