Given the the code below:
public class Item
{
private int _id;
private int _order;
private string _name;
public int Id
{
get { return _id; }
set { _id = value; }
}
public int Order
{
get { return _order; }
set { _order = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public static IList<Item> InitList1()
{
var list = new List<Item>
{
new Item { Id = 1, Order = 1, Name = "Alpha" },
new Item { Id = 2, Order = 2, Name = "Bravo" },
new Item { Id = 3, Order = 3, Name = "Charlie" },
new Item { Id = 4, Order = 4, Name = "Delta" }
};
return list;
}
}
class Program
{
static void Main(string[] args)
{
// Initialize the lists
IList<Item> list1 = Item.InitList1();
IList<Item> list2 = list1.ToList();
IList<Item> list3 = new List<Item>(list1);
// Modify list2
foreach (Item item in list2)
item.Order++;
// Modify list3
foreach (Item item in list3)
item.Order++;
// Output the lists
Console.WriteLine(string.Format("\nList1\n====================="));
foreach (Item item in list1)
Console.WriteLine(string.Format("Item - id: {0} order: {1} name: {2}", item.Id, item.Order, item.Name));
Console.WriteLine(string.Format("\nList2\n====================="));
foreach (Item item in list2)
Console.WriteLine(string.Format("Item - id: {0} order: {1} name: {2}", item.Id, item.Order, item.Name));
Console.WriteLine(string.Format("\nList3\n====================="));
foreach (Item item in list3)
Console.WriteLine(string.Format("Item - id: {0} order: {1} name: {2}", item.Id, item.Order, item.Name));
Console.Write("\nAny key to exit...");
Console.ReadKey();
}
}
The output will be:
List1
=====================
Item - id: 1 order: 3 name: Alpha
Item - id: 2 order: 4 name: Bravo
Item - id: 3 order: 5 name: Charlie
Item - id: 4 order: 6 name: Delta
List2
=====================
Item - id: 1 order: 3 name: Alpha
Item - id: 2 order: 4 name: Bravo
Item - id: 3 order: 5 name: Charlie
Item - id: 4 order: 6 name: Delta
List3
=====================
Item - id: 1 order: 3 name: Alpha
Item - id: 2 order: 4 name: Bravo
Item - id: 3 order: 5 name: Charlie
Item - id: 4 order: 6 name: Delta
Any key to exit...
Can someone please explain to me:
Why after creating the new lists (list2 and list3) that the actions on those lists affects list1 (and subsequently the two other lists)? and
How I can create a new instance of list1 and modify it without affecting list1?
You've effectively got a "shallow copy". That yes, the lists are copied, but they still point to the original items.
Think of it like this. A list doesn't actually contain the items it contains, instead it has a reference to it. So, when you copy your list the new list just contains a reference to the original item. What you need is something like this
IList newlist = new List<Item>();
foreach(item anItem in myList)
{
newList.Add(item.ReturnCopy());
}
where return copy looks something like this:
public Item ReturnCopy()
{
Item newItem = new Item();
newItem._id = _id;
newItem._order = _order;
newItem._name = _name;
return newItem
}
That will copy all the data from the item, but leave the original intact. There are loads of patterns and interfaces that can offer better implementations, but I just wanted to give you a flavour of how it works.
You have 3 lists, but they contain the same 4 elements (ie. references to the same 3 objects in memory). So when you modify order in an item in List1, it also takes effect in the item in List2 - because it is the same object.
Neither ToList nor the List constructor makes a deep copy.
If you want to copy the objects too, you need to copy them also, to create new references to add to the new lists. In .NET, you would typically implement ICloneable<T>
in order to provide a Clone
method. If you don't feel you need that, you can just create new Item
s and copy their properties.
static class Extension
{
public static IList<T> Clone<T>(this IList<T> list) where T: ICloneable
{
return list.Select(i => (T)i.Clone()).ToList();
}
}
Now you can use IList<T>.Clone()
to return objects.
You have 3 distinct lists, and so editing those lists (i.e. adding a new item to the list, removing an item, setting a new item at a given position) is a change that won't affect the other variables.
However, the item in each of the lists only contains a reference to an actual Item
instance, and all three lists have the same three references. When you change the item that is referenced by that list you are making a change that is "visible" from the other lists.
In order to not see this behavior you need to not only create a new list, but ensure that the items in the new list(s) are brand new references to new objects that happen to contain the same values. In the general case, this isn't a trivial task, nor is it often desirable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With