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
Related
I have a list called ListA: List<string> allStuffs = ...
I want to reference the list to ListB as List<string> secondList = allStuffs;
If I do something like secondList.Remove(someitem), would it also remove the same item on allStuffs?
Yes; there is only one list object in this example - whatever the ... is on the first line. The List<string> secondList = allStuffs; doesn't create a new list - it just creates a new reference, with the value copied from allStuffs - which is itself just a reference (not the list itself).
You can have as many references to that list object as you like: they're all just indicators as to where the actual list is.
So if you follow one copy of the reference to the object to call Remove, the change will be visible from any other reference to the same object.
Yes as explained in the above answer it is pointing to the same list. if you don't want to change the first list on change anything on the second then you can use it like this.
List<int> ls1 = new List<int>() { 1, 2, 3 };
List<int> ls2 = new List<int>(ls1);
ls2.Remove(1);
ls1 will still have 1,2 and 3
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);
}
Ive just seen a piece of code that uses a generic list class to instantiate itself in the following manner:
var foo = new List<string>(){"hello", "goodbye"};
The curly braces after the contructor are especially confusing. It reminds me somewhat of
var bar = new string[]{"hi","bye"};
but in the past i've wouldve always used:
var foo = new List<string>(new []{"hello", "goodbye"});
Has anybody got a link explaining the syntax in the first line of code? I wouldnt even know where to begin with googling it.
As others have pointed out, that is a collection initializer. Some other features you might not be aware of that were added to C# 3:
A collection initializer constructor may omit the parentheses if the argument list is empty. So new List<int> { 10, 20, 30 } is fine.
An array initialized with an array initializer may in some cases omit the type. For example, var myInts = new[] { 10, 20, 30}; infers that myInts is int[].
Objects may be initialized using a similar object initializer syntax. var c = new Customer() { Name = "Fred" }; is the same as var temp = new Customer(); temp.Name = "Fred"; var c = temp;
The point of these features is to (1) make more things that used to require statements into things that require only expressions; LINQ likes things to be expressions, and (2) to enable richer type inference, particularly for anonymous types.
Finally: there has been some confusion in some of the answers and comments regarding what is required for a collection initializer. To be used with a collection initializer the type must (1) implement IEnumerable (so that we know it is a collection) and (2) have an Add method (so that we can add stuff to it.)
See
http://blogs.msdn.com/b/madst/archive/2006/10/10/what-is-a-collection_3f00_.aspx
for additional thoughts on the design of the feature.
here you go. The keyword is "Array Initializers".
http://msdn.microsoft.com/en-us/library/aa664573(v=vs.71).aspx
or rather "Collection Initializers"
http://msdn.microsoft.com/en-us/library/bb384062.aspx
This is a collection initializer: http://msdn.microsoft.com/en-us/library/bb384062.aspx
The type so initialized must implement IEnumerable and have an Add method. The items in the curly-brace list are passed to the add method; different items in the list could be passed to different Add methods. If there's an Add overload with more than one argument, you put the multiple arguments in a comma-separated list enclosed in curly braces.
For example:
class MyWeirdCollection : IEnumerable
{
public void Add(int i) { /*...*/ }
public void Add(string s) { /*...*/ }
public void Add(int i, string s) { /*...*/ }
//IEnumerable implementation omitted for brevity
}
This class could be initialized thus:
var weird = new MyWeirdCollection { 1, "Something", {5, "Something else"} };
This compiles to something like this:
var temp = new MyWeirdCollection();
temp.Add(1);
temp.Add("Something");
temp.Add(5, "Something else");
var weird = temp;
In his blog post (link posted by Eric Lippert in the comments), Mads Torgersen expresses this concisely:
The list you provide is not a “list of elements to add”, but a “list of sets of arguments to Add methods”. ...[W]e do separate overload resolution against Add methods for each entry in the list.
In the third line of code you provided you are making a new string array, and then passing that string array to the list. The list will then add each of those items to the list. This involves the extra overhead of allocating the array, populating it, and then discarding it.
There is a mechanism for a class to define how to use Collection Initializers to populate itself. (See the other answers) I have never found the need to utilize this for my own classes, but existing data structures such as List, Dictionary, often define them, and they are useful to use.
This is a collection initializer. You can use it on collections with an Add method.
The pair of parentheses before the curly braces is optional.
This is very convenient, because you can use it on collections other than lists, for example on dictionaries:
var x = new Dictionary<int,string> {{1, "hello"}, {2, "world"}};
This lets you avoid a lengthier initialization sequence:
var x = new Dictionary<int,string>();
x.Add(1, "hello");
x.Add(2, "world");
If I did not get this terribly wrong, this behaviour is strange for me. Rather than explaining, I'll post a sample code below and please tell me why does I get output x and not y.
private void button1_Click(object sender, EventArgs e)
{
List<int> l = new List<int>() { 1, 2, 3 };
Fuss(l);
MessageBox.Show(l.Count.ToString()); // output is 5
}
private void Fuss(List<int> l)
{
l.Add(4);
l.Add(5);
}
Output should, I assume would be 3. But I get the output as 5. I understand the output can be 5 if I do this:
private void button1_Click(object sender, EventArgs e)
{
List<int> l = new List<int>() { 1, 2, 3 };
Fuss(ref l);
MessageBox.Show(l.Count.ToString()); // output is 5
}
private void Fuss(ref List<int> l)
{
l.Add(4);
l.Add(5);
}
It does not act like its passed by ref.
void ChangeMe(List<int> list) {
list = new List<int>();
list.Add(10);
}
void ChangeMeReally(ref List<int> list) {
list = new List<int>();
list.Add(10);
}
Try it. Do you notice the difference?
You can only change the contents of list (or any reference type) if you pass it without a ref (because as others have said, you are passing a reference to the object on the heap and thus change the same "memory").
However you cannot change "list", "list" is a variable that points to an object of type List. You can only change "list" if you pass it by reference (to make it point somewhere else). You get a copy of the reference, which if changed, can only be observed inside your method.
Parameters are passed by value in C# unless they are marked with the ref or out modifiers. For reference types, this means that the reference is passed by value. Therefore, in Fuss, l is referring to the same instance of List<int> as its caller. Therefore, any modifications to this instance of List<int> will be seen by the caller.
Now, if you mark the parameter l with ref or out, then the parameter is passed by reference. What this means is that in Fuss, l is an alias for storage location used as a parameter to invoke the method. To be clear:
public void Fuss(ref List<int> l)
called by
List<int> list = new List<int> { 1, 2, 3 };
Fuss(list);
Now, in Fuss, l is an alias for list. In particular, if you assign a new instance of List<int> to l, the caller will see that new instance assigned to the variable list as well. In particular, if you say
public void Fuss(ref List<int> l) {
l = new List<int> { 1 };
}
then the caller will now see a list with one element. But if you say
public void Fuss(List<int> l) {
l = new List<int> { 1 };
}
and call by
List<int> list = new List<int> { 1, 2, 3 };
Fuss(list);
then the caller will still see list as having three elements.
Clear?
ByRef and ByVal only apply to value types, not to reference types, which are always passed as though they were "byref".
If you need to modify a list discreetly, use the ".ToList()" function, and you'll get a clone of your list.
Keep in mind that if your list contains reference types, your "new" list contains pointers to the same objects that your original list did.
Lists are already reference types, so when you pass them to a method, you are passing a reference. Any Add calls will affect the list in the caller.
Passing a List<T> by ref behaves essentially like passing a double-pointer to that list. Here's an illustration:
using System;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
List<int> l = new List<int>() { 1, 2, 3 };
Fuss(l);
Console.WriteLine(l.Count); // Count will now be 5.
FussNonRef(l);
Console.WriteLine(l.Count); // Count will still be 5 because we
// overwrote the copy of our reference
// in FussNonRef.
FussRef(ref l);
Console.WriteLine(l.Count); // Count will be 2 because we changed
// our reference in FussRef.
}
private static void Fuss(List<int> l)
{
l.Add(4);
l.Add(5);
}
private static void FussNonRef(List<int> l)
{
l = new List<int>();
l.Add(6);
l.Add(7);
}
private static void FussRef(ref List<int> l)
{
l = new List<int>();
l.Add(8);
l.Add(9);
}
}
A variable, parameter, or field of type "List", or any other reference type, doesn't actually hold a list (or object of any other class). Instead, it will hold something like "Object ID #29115" (not such an actual string, of course, but a combination of bits which means essentially that). Elsewhere, the system will have an indexed collection of objects called the heap; if some variable of type List holds "Object ID #29115", then object #29115 in the heap will be an instance of List or some type derived therefrom.
If MyFoo is a variable of type List, a statement like 'MyFoo.Add("George")' won't actually change MyFoo; instead, it means "Examine the object ID stored in MyFoo, and invoke the "Add" method of the object stored therein. If MyFoo held "Object ID #19533" before the statement executed, it will continue to do so afterward, but Object ID #19533 will have had its Add method invoked (probably altering that object). Conversely, a statement like "MyFoo = MyBar" will make MyFoo hold the same object-id as MyBar, but won't actually do anything to the objects in question. If MyBar held "Object ID #59212" before the statement, then after the statement, MyFoo will also hold "ObjectId #59212". Nothing will have happened to object ID #19533, nor object ID#59212.
The difference between ref and non-ref for reference types like List is not whether you pass a reference (that happens always), but whether that reference can be changed. Try the following
private void Fuss(ref List<int> l)
{
l = new List<int> { 4, 5 };
}
and you'll see the count is 2, because the function not only manipulated the original list but the reference itself.
Only primitive types like int, double etc. are passed by value.
Complex types (like list) are passed via reference (which is a passing pointer by value, to be exact).
lets explain it Easy :)
"Fuss" in your first chunk of code knows that he should accept a refrence from a list type
"Fuss" in your second chunk of code knows that he should accept nothing! but just a refrence to "sth else" which accidently this "sth else" is the same thing which was in your first chunk of code 🤣♥
if it seems confusing i think you should have a deep understanding of what a reference is
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.