I am using an ImmutableList as follows:
Referenced the package using Nuget and following is the usage code:
using System.Collections.Immutable;
private ImmutableList<Data> immutableList = ImmutableList.Create<Data>();
// Write Action
Action writeAction = (() =>
{
Data writeData = new Data();
// Fill Data type with valid values
immutableList.Add(writeData);
});
This code above is not adding any data to the Immutable list. It remains empty, I cannot figure out the reason when all the data is valid. Similar code is used to fill other data structures like ConcurrentQueue and ConcurrentBag and it works fine.
Am I missing something in the usage of the immutable list, does it requires correction?
Please note this is a multi-threaded operation, but that can't be an issue, since this data structure is thread safe.
As the name suggest list is immutable i.e. you cannot add the item to original list. Under remarks section of MSDN link:
When you add or remove items from an immutable list copy of the
original list is made with the items added or removed, and the
original list is unchanged.
Also from here, of Add method documentation:
It returns a new immutable list with the object added, or the current list if it
already contains the specified object.
Add will get you new list reference with item added in it (original list will remain unchanged):
immutableList = immutableList.Add(writeData);
Immutable list is a list that does not change. Here is a description from MSDN on what it means:
When you add or remove items from an immutable list copy of the original list is made with the items added or removed, and the original list is unchanged.
This means that every time you perform operation like Add, your original list is not changed, but the new list with added element is returned. This means that you would need to use a code like this to have the correct list:
immutableList = immutableList.Add(writeData);
This makes me think that you are using it for wrong scenario.
Create your normal list... Turn it into Array
Use that array to make immutable list... heres my snippet
var result = csvReader.GetRecords<Data>().ToArray();
return ImmutableList.Create<Data>(result);
ImmutableList immutableList = ImmutableList.Create<string>("data1", "data2");
This works perfectly for me.
The answers already states that the immutable list is really immutable, when you add items, you must designate the new immutable list from the add operation to the same variable for example.
A possibility for easier use is to wrap the immutable list with a functional container class like the following code, which can be pasted in Linqpad 5 (make sure you hit F4 to add Nuget reference to System.Collections.Immutable and pick the namespace from that assembly).
void Main()
{
var numbersInImmutableList = new ImmutableWrappedList<int>();
numbersInImmutableList.AddRange(new[] { 3, 1, 4, 1, 5, 9, 2 });
numbersInImmutableList.AddRange(new[]{ 2, 7, 1, 8, 2, 1, 8 });
numbersInImmutableList.RemoveAt(2);
numbersInImmutableList.Dump();
}
public class ImmutableWrappedList<T> {
public ImmutableList<T> _internalList {get; private set; }
public ImmutableWrappedList()
{
_internalList = ImmutableList.Create<T>();
}
public void Clear() => _internalList.Clear();
public void AddRange(IEnumerable<T> itemsToAdd) => _internalList = _internalList.AddRange(itemsToAdd);
public void Add(T itemToAdd) => _internalList = _internalList.Add(itemToAdd);
public void Remove(T itemToAdd) => _internalList = _internalList.Remove(itemToAdd);
public void RemoveAt(int index) => _internalList = _internalList.RemoveAt(index);
public void Insert(T itemToAdd, int position) => _internalList = _internalList.Insert(position, itemToAdd);
}
Related
public class Foo
{
public static List<long> myList = new List<long>() { 1,2,3 }
}
In another method:
var testList = Foo.myList;
If I put a breakpoint at the last line and inspect testList it gives me different lengths from time to time.
When I use ToList() on Foo.myList it seems to behave correctly. But why?
Edit:
My problem was that I made an ajax call > modified Foo.myList > new ajax call > fetched Foo.myList again and got the modified value.
Race condition on shared state. The static field member means there's one copy, so if you manipulate the list in your code, it changes for ALL threads using the property. ToList() works because it creates a copy of the list which won't alter the original list, but note that this copy also points to the same objects as the original list if the objects are reference types. Therefore altering the reference types in the copy would also alter the values in the original list... but since long is a value type that won't apply here.
If you want your list to be read-only http://msdn.microsoft.com/en-us/library/e78dcd75.aspx
It sounds like you're modifying Foo.myList or a reference to it somewhere. Note that assigning the list to a local variable does not make a copy. Thus:
var list = new List<long> { 1, 2, 3 };
var testList = list;
testList.Add(4); // list is now [1, 2, 3, 4]
list.Add(5); // testList is now [1, 2, 3, 4, 5]
ToList(), on the other hand, makes a copy. In general, it's probably safest to make any static lists read only (if that's the semantics you want) to prevent this from happening accidentally:
public class Foo {
// pre .NET 4.5, use ReadOnlyCollection<T> (which implements IList<T>)
public static readonly IReadOnlyList<long> myList = new List<long> { 1, 2, 3 }.AsReadOnly();
}
var testList = Foo.myList.ToList(); // get an editable copy
var testList2 = Foo.myList; // get a reference to the immutable static list
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 list based on some condition.
As can be seen in the below code I am doing some operation on the target list. The problem is that whatever changes I am doing to the target list is also being done to the mainList. I think its because of the reference is same or something.
All I need is that operation on the target list not affect data inside the main list.
List<Item> target = mainList;
SomeOperationFunction(target);
void List<Item> SomeOperationFunction(List<Item> target)
{
target.removeat(3);
return target;
}
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;
}
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());
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;
}
I tried many of the answers above. On all the ones I tested, an update to the new list modifies the original. this is what works for me.
var newList = JsonConvert.DeserializeObject<List<object>>(JsonConvert.SerializeObject(originalList));
return newlist.RemoveAt(3);
Even if you create a new list, the references to the items in the new list will still point to the items in the old list, so I like to use this extension method if I need a new list with new references...
public static IEnumerable<T> Clone<T>(this IEnumerable<T> target) where T : ICloneable
{
If (target.IsNull())
throw new ArgumentException();
List<T> retVal = new List<T>();
foreach (T currentItem in target)
retVal.Add((T)(currentItem.Clone()));
return retVal.AsEnumerable();
}
Your target variable is a reference type. This means that anything you do to it will be reflected in the list you pass into it.
To not do that, you are going to need to create a new list in the method, copy target contents to it, and then perform the remove at operation on the new list.
About Reference and Value Types
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.
Your are seeing the original list being modified because, by default, any non-primitive objects, are passed by reference (It is actually pass by value, the value being the reference, but that is a different matter).
What you need to do is clone the object. This question will help you with some code to clone a List in C#: How do I clone a generic list in C#?
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.
Just make sure that you initialize the new list with a list created by copying the elements of the source list.
List<Item> target = mainList; Should be List<item> target = new List<Item>(mainList);
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.
I am aware that C# does not deal with pointers but I wonder if I can get a ref to a list when I know its first element?
For example:
Let's say I have a list defined as
List<T> abc
If I have abc[0], can I get a reference of abc?
I am new to C#, I apologize if my question seems weird. In C/C++, I can get the address of an array abc by using &abc[0]. Does C# provide us with similar tool that help us refer back to the collection itself when we know one item in the collection?
Thanks,
This is now possible, starting with .NET 5.0, by using the System.Runtime.InteropServices.CollectionsMarshal.AsSpan method.
As indicated by the documentation, items should not be added to or removed from the list while using the span or item references taken from the span. Technically this should also be extended to say that the Capacity should not be changed nor should TrimExcess() be called. If these operations are used while actively using the span or its references, then the internal memory of the list may no longer be the same as the memory in the span.
// Create a simple list with three items.
var list = new List<int>();
list.Add(123);
list.Add(456);
list.Add(789);
// Print list to console.
Console.WriteLine("List items:");
foreach (var item in list)
Console.WriteLine(item);
Console.WriteLine();
// Get a reference to the second item in the list.
// WARNING: DO NOT ADD/REMOVE ITEMS FROM THE LIST WHILE USING THIS SPAN
// OR ANY REFERENCES DERIVED FROM THIS SPAN!
var listSpan = CollectionsMarshal.AsSpan(list);
ref var secondItem = ref listSpan[1];
Console.WriteLine($"Referenced value (original): {secondItem}");
// Change the referenced list item.
secondItem = 0;
Console.WriteLine($"Referenced value (modified): {secondItem}");
Console.WriteLine();
// Print the list to console.
Console.WriteLine("List items:");
foreach (var item in list)
Console.WriteLine(item);
Console.WriteLine();
You should get output like this:
List items:
123
456
789
Referenced value (original): 456
Referenced value (modified): 0
List items:
123
0
789
Collections don't work the same way in C# as they do in C++, for example you can add the same object to multiple different collections and so it doesn't really make sense to ask to get a reference to the list that an object is contained in, as it could be in many lists (or none, or even in the same list multiple times)
object myObject = new object();
List<object> list = new List<object>();
list.Add(myObject);
object[] someArray = new object[] { myObject };
Assert.AreEqual(list[0], someArray[0]);
If it helps you can think of lists in C# as being lists of pointers references to the objects being stored where the pointer itself is hidden from you, although understand that in reality the implementation may be more complicated (and is also irrelevant).
If there is a relationship between the objects in a list and the list contents of that list then its up to you to explicitly declare and keep track of what that realtionsip is, for example through a Parent property on the object in the list
List<T> myList = new List<T>();
// Whenever an item is added to myList set the Parent property
myList.Add(item);
item.Parent = myList;
This is what Windows Forms does in order to maintain the relationship between the controls in a container, and the container in which those controls are contained. Obviously you should decide what to do if someone tries to add the same object to multiple lists.
Not unless the type of abc[0] explicitly holds a reference to the list. In fact you cannot do that in C++ either without an explicit reference.
Think about it, in C++ if you can expect firstElemPtr == arrayPtr it is just because arrays store the elements that way and it only works for arrays; everything else is just by accident.
Now consider any list structure that allocates something else (maybe element count) before the pointer to the first element. Your assumption will not work anymore.
If you are designing the type of the items in the collection, then you can add a property to the item's type that "points" to the containing list; when you construct each item, pass in the containing list and save this in the property.
Something like this:
class ListItem
{
public List<ListItem> Parent { get; set; }
public ListItem(List<ListItem> parent)
{
Parent = parent;
}
}
ListItem listItem = new ListItem(abc);
abc.Add(listItem);
// Get collection from item.
List<T> def = listItem.Parent;
Consider:
unsafe static void Main() {
int[] arr = new int[100];
fixed(int* ptr = arr) {
// ptr is a pointer to the zeroth item in the array
}
}
However, unsafe code is not all that common in c# and should be limited to performance-critical regions (and even then used sparingly). In particular, note that we have "pinned" the array by doing this - and note that ptr is only reliable while it is pinned. Outside of the fixed block, GC is free to relocate the array, making ptr invalid.
Clarification: I don't suggest you should do this, but: such things are entirely possible.
List is defined somewhat like this:
public class List<T> : IList<T> blabla
{
private T [] data;
public T this[int index] {
get { return data[index]; }
set { data[index]=value; }
}
... blabla
}
YES, it is NOT linked list of any kind. So you must use it accordingly. Though since .NET value types are small and class types are all references, there usually no heavy array-copy operations as it is possible with C++ for example so such implementation of general-puprose collection is good enough (unless abused). Vector could be a better name from academic standpoint, but it's not.
You would not be able to get a reference to data array, as it's private variable. Nor you would have any need for this. If you need enumerator, use GetEnumerator explicitely or foreach for implicit use.
Let's say I have a class
public class MyObject
{
public int SimpleInt{get;set;}
}
And I have a List<MyObject>, and I ToList() it and then change one of the SimpleInt, will my change be propagated back to the original list. In other words, what would be the output of the following method?
public void RunChangeList()
{
var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
return objects[0].SimpleInt;
}
Why?
P/S: I'm sorry if it seems obvious to find out. But I don't have compiler with me now...
Yes, ToList will create a new list, but because in this case MyObject is a reference type then the new list will contain references to the same objects as the original list.
Updating the SimpleInt property of an object referenced in the new list will also affect the equivalent object in the original list.
(If MyObject was declared as a struct rather than a class then the new list would contain copies of the elements in the original list, and updating a property of an element in the new list would not affect the equivalent element in the original list.)
From the Reflector'd source:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new List<TSource>(source);
}
So yes, your original list won't be updated (i.e. additions or removals) however the referenced objects will.
ToList will always create a new list, which will not reflect any subsequent changes to the collection.
However, it will reflect changes to the objects themselves (Unless they're mutable structs).
In other words, if you replace an object in the original list with a different object, the ToList will still contain the first object.
However, if you modify one of the objects in the original list, the ToList will still contain the same (modified) object.
Yes, it creates a new list. This is by design.
The list will contain the same results as the original enumerable sequence, but materialized into a persistent (in-memory) collection. This allows you to consume the results multiple times without incurring the cost of recomputing the sequence.
The beauty of LINQ sequences is that they are composable. Often, the IEnumerable<T> you get is the result of combining multiple filtering, ordering, and/or projection operations. Extension methods like ToList() and ToArray() allow you to convert the computed sequence into a standard collection.
The accepted answer correctly addresses the OP's question based on his example. However, it only applies when ToList is applied to a concrete collection; it does not hold when the elements of the source sequence have yet to be instantiated (due to deferred execution). In case of the latter, you might get a new set of items each time you call ToList (or enumerate the sequence).
Here is an adaptation of the OP's code to demonstrate this behaviour:
public static void RunChangeList()
{
var objs = Enumerable.Range(0, 10).Select(_ => new MyObject() { SimpleInt = 0 });
var whatInt = ChangeToList(objs); // whatInt gets 0
}
public static int ChangeToList(IEnumerable<MyObject> objects)
{
var objectList = objects.ToList();
objectList.First().SimpleInt = 5;
return objects.First().SimpleInt;
}
Whilst the above code may appear contrived, this behaviour can appear as a subtle bug in other scenarios. See my other example for a situation where it causes tasks to get spawned repeatedly.
A new list is created but the items in it are references to the orginal items (just like in the original list). Changes to the list itself are independent, but to the items will find the change in both lists.
Just stumble upon this old post and thought of adding my two cents. Generally, if I am in doubt, I quickly use the GetHashCode() method on any object to check the identities. So for above -
public class MyObject
{
public int SimpleInt { get; set; }
}
class Program
{
public static void RunChangeList()
{
var objs = new List<MyObject>() { new MyObject() { SimpleInt = 0 } };
Console.WriteLine("objs: {0}", objs.GetHashCode());
Console.WriteLine("objs[0]: {0}", objs[0].GetHashCode());
var whatInt = ChangeToList(objs);
Console.WriteLine("whatInt: {0}", whatInt.GetHashCode());
}
public static int ChangeToList(List<MyObject> objects)
{
Console.WriteLine("objects: {0}", objects.GetHashCode());
Console.WriteLine("objects[0]: {0}", objects[0].GetHashCode());
var objectList = objects.ToList();
Console.WriteLine("objectList: {0}", objectList.GetHashCode());
Console.WriteLine("objectList[0]: {0}", objectList[0].GetHashCode());
objectList[0].SimpleInt = 5;
return objects[0].SimpleInt;
}
private static void Main(string[] args)
{
RunChangeList();
Console.ReadLine();
}
And answer on my machine -
objs: 45653674
objs[0]: 41149443
objects: 45653674
objects[0]: 41149443
objectList: 39785641
objectList[0]: 41149443
whatInt: 5
So essentially the object that list carries remain the same in above code. Hope the approach helps.
I think that this is equivalent to asking if ToList does a deep or shallow copy. As ToList has no way to clone MyObject, it must do a shallow copy, so the created list contains the same references as the original one, so the code returns 5.
ToList will create a brand new list.
If the items in the list are value types, they will be directly updated, if they are reference types, any changes will be reflected back in the referenced objects.
In the case where the source object is a true IEnumerable (i.e. not just a collection packaged an as enumerable), ToList() may NOT return the same object references as in the original IEnumerable. It will return a new List of objects, but those objects may not be the same or even Equal to the objects yielded by the IEnumerable when it is enumerated again
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
This will update the original object as well. The new list will contain references to the objects contained within it, just like the original list. You can change the elements either and the update will be reflected in the other.
Now if you update a list (adding or deleting an item) that will not be reflected in the other list.
I don't see anywhere in the documentation that ToList() is always guaranteed to return a new list. If an IEnumerable is a List, it may be more efficient to check for this and simply return the same List.
The worry is that sometimes you may want to be absolutely sure that the returned List is != to the original List. Because Microsoft doesn't document that ToList will return a new List, we can't be sure (unless someone found that documentation). It could also change in the future, even if it works now.
new List(IEnumerable enumerablestuff) is guaranteed to return a new List. I would use this instead.
I have a list, and I want to provide read-only access to a collection containing its contents. How can I do this?
Something like:
public ICollection<Foo> ImmutableViewOfInventory() {
IList<Foo> inventory = new List<Foo>();
inventory.add(new Foo());
return inventory.ImmutableView();
}
Additionally, an immutable IEnumerable would also be fine.
UPDATE: I realize now that an immutable view of the list would actually be better. (Preserving list ordering semantics.)
This won't give me list behavior, right:
public ReadOnlyCollection<PickUp> InventoryItems()
{
return new ReadOnlyCollection<PickUp>(inventory);
}
I'm looking in the documentation but not immediately seeing ReadOnlyList<T>.
If you are wanting an immutable list of the items, you can return a ReadOnlyCollection by calling the AsReadOnly() method on your list:
public IList<Foo> ImmutableViewOfInventory()
{
List<Foo> inventory = new List<Foo>();
inventory.Add(new Foo());
return inventory.AsReadOnly();
}
This returns an implementation of IList that is both strongly-typed and not modifiable.
It does not however prevent changes to any of the items contained in the list (unless they are value types). To do that, each item must be cloned (deep-cloned if they themselves contain other objects) and added to a new read only list that is returned from your ImmutableViewOfInventory method. You will have to implement this yourself unfortunately.
Have you looked at ReadOnlyCollection<T>?
http://msdn.microsoft.com/en-us/library/ms132474.aspx
new ReadOnlyCollection(inventory);