1

I have a class.

public class abc
{
    public int i = 0;
    public string a = "";
}

=======================================

Now, I am inserting some records in list of type abc class

List<abc> c = new System.Collections.Generic.List<abc>();
abc a = new abc();
a.a = "1";
a.i = 1;
c.Add(a);

a = new abc();
a.a = "1";
a.i = 2;
c.Add(a);

===========================================

Creating a list variable and adding some filtered records.

List<abc> temp = new System.Collections.Generic.List<abc>();

temp.AddRange(c.Where(i => i.i == 1));

===============================================

Query = by executing the below lines of code will change the c variable as well.

I know both points to same memory location. Is there any way to fix this code?

foreach (abc d in temp)
{
    d.i = 10;
}
sehe
  • 374,641
  • 47
  • 450
  • 633

3 Answers3

4

It is not "Why updating the list updates another list?"

It is "Why updating an instance in a list updates the same instance in another list?"

Because you are using a class and the same instances of this class.

List<abc> list1 = new List<abc>();
list1.Add(new abc());  // new abc() creates an instance of the abc() class. Let's call this instance myInstance

List<abc> list2 = new List<abc>();
list2.Add(list1[0]);  // Here you add the same instance (ie. myInstance) to the list2

list1[0].a = 5;  // You modify the instance myinstance

Console.WriteLine(list2[0].a);   // Returns "5"  (because it is always the same instance myIsntance)

To avoid this behavior you have 2 solutions:

Create a Clone method to clone an instance of abc with the same value.

public class abc
{
    public int i = 0;
    public string a = "";

    public abc Clone(abc instanceToClone)
    {
        abc result = new abc();
        result.i = instanceToClone.i;
        result.a = instanceToClone.a;
    }
}

Or replace the class by a struct (then you have a value type but you can't have field initializers)

public struct abc
{
    public int i;  // Initialized by default to 0
    public string a;  // Initialized by default to null
}

I suggest you to read this excelent article to understand the "basic" concepts of C#. (not so easy but really important)

Cédric Bignon
  • 12,892
  • 3
  • 39
  • 51
3

Create clones of your objects whenever you need to. For example, if i and a were properties -- which they should totally be! -- you could have written

temp.AddRange(c.Where(i => i.i == 1).Select(o => new abc { a = o.a, i = o.i}));
Jon
  • 428,835
  • 81
  • 738
  • 806
  • So that means in terms of Lambda Expressions, New instance should be created ? –  Jan 29 '13 at 13:04
  • @PankajGarg: Yes, it means "for each matching item `o`, create a new abc instance with..." (basically cloning the current instance). The clones are what gets added to `temp`. – Jon Jan 29 '13 at 13:19
0

Updates made to object instance are visible to every owner of that instance. It doesn't matter in how many collections object is located, or what type of collections contain it, changes will be visible everywhere. This is simply because collections only point to same location in memory. Irregardless where you make the change, it will be visible everywhere.

If you need to avoid such behavior, you have 2 options:

  • clone objects within one collection
  • use struct instead of a class


public struct abc
{
    int i;
    string a;
}

abc a, b;
...
a.i = 1;
b = a;
/* new memory location is allocated for `b`, and values are copied from `a`.
therefore, updates made to `a` will not affect `b`*/
b.i = 2;
if (a.i == b.i)
    throw new Exception("i values are same");
Michael Celey
  • 12,645
  • 6
  • 57
  • 62
Nikola Radosavljević
  • 6,871
  • 32
  • 44