0

Hi I have a list with Person class as follows

public class person
{
    public int age;
    public string name;
}

I am trying to do the following.

static void Main(string[] args)
{
    List<person> person1 = new List<person>();
    person1.Add(new person { age = 10, name = "P1" });
    person1.Add(new person { age = 11, name = "Q1" });
    person1.Add(new person { age = 12, name = "R1" });

    List<person> person2 = new List<person>(person1);
    person2[0].name = "P2";
    Console.WriteLine("---------Person1---------");

    foreach (person P in person1)
    {
        Console.WriteLine("Age=" + P.age);
        Console.WriteLine("Name=" + P.name);
    }
    Console.WriteLine("---------Person2---------");
    foreach (person P in person2)
    {
        Console.WriteLine("Age=" + P.age);
        Console.WriteLine("Name=" + P.name);
    }
}

The Output is that the value of first object in both the lists is changed to P2 while I expect to change it only in person2 list. I thought the list items would be copied into person2 list. MSDN here says that the elements are copied to the new list which is not happening in above case. what am I missing here?

Sudheesh Singanamalla
  • 2,283
  • 3
  • 19
  • 36
Programmerzzz
  • 1,237
  • 21
  • 48
  • 2
    The elements will be copied, which means with objects that their references are copied. No new objects are created. This is a bit misleading wording in MSDN, better leave a comment there so they could clarify. – Sami Kuhmonen Mar 19 '18 at 05:41

3 Answers3

1

The mistake you're making here is with reference variables. What's held in the list are references to objects of type person. When you copy the list, it only copies the references to these objects, so each list contains references to exactly the same set of objects.

For a more in depth example of what I'm talking about, consider the following code:

person me = new person { age = 20, name = "Lauraducky" };
person you = me;
you.name = "Programmerzzz";
Console.WriteLine(me.name); // Outputs Programmerzzz

This is essentially what you're doing in your example. The me variable doesn't get copied, a reference to it just gets passed to the you variable. Then the object at that reference location is changed. The key here being that both variables point to the same location.

If you want to make a deep copy of the list, you'll have to do so manually. For example:

List<person> person2 = new List<person>();
foreach (person p in person1) {
    person2.Add(new person { age = p.age, name = p.name });
}

For more reading about reference types, see this excellent explanation.

Lauraducky
  • 674
  • 11
  • 25
0

Class is copy by reference, struct is copy by value.

So you change the people's value , you will link to a original reference.

public Struct person
{
    public int age;
    public string name;
}

And if you use struct, try again, you will see different

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
TimChang
  • 2,249
  • 13
  • 25
  • Using structs for everything isn't particularly good advice as objects get larger and more cumbersome. Structs have a very specific use case. I think it's much better to learn to work with classes and take the benefits of passing things by reference. – Lauraducky Mar 19 '18 at 05:59
  • Yes , I can't agree with you anymore , copy by value usually use more performance. – TimChang Mar 19 '18 at 06:16
0

You're copying by reference and not by value. First thing to do is fix your class. So you can create 'person' objects using a constructor. The code below creates a new object rather than copying the reference of the former list.

public static void Main()
{

    Console.WriteLine("Program Started!");

    List<person> person1 = new List<person>();
    person1.Add(new person(10, "P1" ));
    person1.Add(new person( 11, "Q1" ));
    person1.Add(new person(12,  "R1" ));

    List<person> person2 = new List<person>();
    foreach(person p in person1)
    {
        person2.Add(new person(p)); //WE COPY BY VALUE. BY ALLOCATING SPACE FOR A NEW OBJECT.
    }

    person2[0].name = "P2";
    Console.WriteLine("---------Person1---------");

    foreach (person P in person1)
    {
        Console.WriteLine("Age=" + P.age);
        Console.WriteLine("Name=" + P.name);
    }
    Console.WriteLine("---------Person2---------");
    foreach (person P in person2)
    {
        Console.WriteLine("Age=" + P.age);
        Console.WriteLine("Name=" + P.name);
    }

    Console.WriteLine("Program Ended!");
    Console.ReadKey();
}

public class person
{
    public int age;
    public string name;

    public person(person p) {
        this.age = p.age;
        this.name = p.name;
    }

    public person(int _age, string _name)
    {
        this.age = _age;
        this.name = _name;
    }

}
Kent Kostelac
  • 2,257
  • 3
  • 29
  • 42