First of all, let's see how to copy a list in the simplest way with two simple List<int>.
- List<int> listA = new List<int>() { 10, 20 };
- List<int> listB = new List<int>() { };
- listB = listA.Select(x => { x = 0; return x; }).ToList();
It works without any problem and the result is given below.
ListA:
[0]: 10
[1]: 20
ListB:
[0]:0
[1]:0
Now, let's see what happens, if we try it with a reference type.
- List<string> listA = new List<string>() { "Peter", "Eve" };
- List<string> listB = new List<string>() { };
- listB = listA.Select(x => { x = "Doe"; return x; }).ToList();
Fortunately, it works again and the result is shown below.
ListA:
[0]: Peter
[1]: Eve
ListB:
[0]:Doe
[1]:Doe
Thus, basically copying a list doesn't depend solely on the value or the reference types, since it worked the same way with both the types.
Let's see what happens, if we try it with a complex type.
Let's create a simple class, as shown below.
- class Person
- {
- public string Firstname { get; set; }
- public string Lastname { get; set; }
- }
Now, proceed with the code given below.
- List<Person> listA = new List<Person>()
- { new Person() { Firstname = "Douglas", Lastname = "Adams" },
- new Person() { Firstname = "Kurt", Lastname = "Vonnegut" }
- };
-
- List<Person> listB = new List<Person>();
- listB = listA.Select(x => { x.Lastname = "Doe"; return x; }).ToList<Person>();
Unfortunately, it doesn't work, as we expected, and the result is shown below.
ListA:
[0]: Firstname:Douglas, Lastname:Doe
[1]: Firstname:Kurt, Lastname:Doe
ListB:
[0]:Firstname:Douglas, Lastname:Doe
[1]:Firstname:Kurt, Lastname:Doe
As we can see the elements changed in both the lists, despite the desire to modify only in the listB. Obviously the problem is that copying creates our listB with the elements but still each element has a reference to the element of the listA.
The solution for copying of complex types is the cloning, as we do it in every similar cases.
First of all, let's complete the class with the IClonable interface and implement the necessary Clone interface method.
- class Person : ICloneable
- {
- public string Firstname { get; set; }
- public string Lastname { get; set; }
-
- public object Clone()
- {
- Person newPerson = (Person)this.MemberwiseClone();
- return newPerson;
- }
- }
Subsequently, proceed with the code given below.
- List<Person> listA = new List<Person>()
- { new Person() { Firstname = "Douglas", Lastname = "Adams" },
- new Person() { Firstname = "Kurt", Lastname = "Vonnegut" }
- };
-
- List<Person> listB = new List<Person>();
- listB = listA.Select(x => { return (Person)x.Clone(); }).ToList<Person>();
- listB = listB.Select(x => { x.Lastname = "Doe"; return x; }).ToList<Person>();
In this way, the listB is going to contain the clones of the listA elements, so the modification of the Lastname doesn't have an affect on the elements of the listA.
ListA:
[0]: Firstname:Douglas, Lastname:Adams
[1]: Firstname:Kurt, Lastname:Vonnegut
ListB:
[0]:Firstname:Douglas, Lastname:Doe
[1]:Firstname:Kurt, Lastname:Doe
Obviously, we have to pay attention to the types of the properties in the class because we have to provide cloneable complex types, if we want to get decoupled elements for the listB.