I have a list that gets filled in with some data from an operation and I am storing it in the memory cache. Now I want another list which contains some sub data from the li
Build a new list first and operate on that, because List is a reference type, i.e. when you pass it in a function, you do not just pass the value but the actual object itself.
If you just assign target
to mainList
, both variables point to the same object, so you need to create a new List:
List<Item> target = new List<Item>(mainList);
void List<Item> SomeOperationFunction()
makes no sense, because either you return nothing (void
) or you return a List<T>
. So either remove the return statement from your method or return a new List<Item>
. In the latter case, I would rewrite this as:
List<Item> target = SomeOperationFunction(mainList);
List<Item> SomeOperationFunction(List<Item> target)
{
var newList = new List<Item>(target);
newList.RemoveAt(3);
return newList;
}
Instead of assigning mainList to target, I would do: target.AddRange(mainList);
Then you will have a copy of the items instead of a reference to the list.
You need to make a copy of the list so that changes to the copy won't affect the original. The easiest way to do that is to use the ToList
extension method in System.Linq
.
var newList = SomeOperationFunction(target.ToList());
You need to clone your list in your method, because List<T>
is a class, so it's reference-type and is passed by reference.
For example:
List<Item> SomeOperationFunction(List<Item> target)
{
List<Item> tmp = target.ToList();
tmp.RemoveAt(3);
return tmp;
}
Or
List<Item> SomeOperationFunction(List<Item> target)
{
List<Item> tmp = new List<Item>(target);
tmp.RemoveAt(3);
return tmp;
}
or
List<Item> SomeOperationFunction(List<Item> target)
{
List<Item> tmp = new List<Item>();
tmp.AddRange(target);
tmp.RemoveAt(3);
return tmp;
}
Since a List
is a reference type, what is passed to the function is a reference to the original list.
See this MSDN article for more information about how parameters are passed in C#.
In order to achieve what you want, you should create a copy of the list in SomeOperationFunction
and return this instead. A simple example:
void List<Item> SomeOperationFunction(List<Item> target)
{
var newList = new List<Item>(target);
newList.RemoveAt(3);
return newList; // return copy of list
}
As pointed out by Olivier Jacot-Descombes in the comments to another answer, it is important to bear in mind that
[...] the list still holds references to the same items if the items are of a reference type. So changes to the items themselves will still affect the items in both lists.
You'll need to make a copy of the list since in your original code what you're doing is just passing around, as you correctly suspected, a reference (someone would call it a pointer).
You could either call the constructor on the new list, passing the original list as parameter:
List<Item> SomeOperationFunction(List<Item> target)
{
List<Item> result = new List<Item>(target);
result.removeat(3);
return result;
}
Or create a MemberWiseClone:
List<Item> SomeOperationFunction(List<Item> target)
{
List<Item> result = target.MemberWiseClone();
result.removeat(3);
return result;
}
Also, you are not storing the return of SomeOperationFunction
anywhere, so you might want to revise that part as well (you declared the method as void
, which should not return anything, but inside it you're returning an object).
You should call the method this way:
List<Item> target = SomeOperationFunction(mainList);
Note: the elements of the list will not be copied (only their reference is copied), so modifying the internal state of the elements will affect both lists.