I have this struct:
struct Map { public int Size; public Map ( int size ) { this.Size = size; } public override string ToString ( ) { return String.Format ( "Size: {0}", this.Size ); } }
When using array, it works:
Map [ ] arr = new Map [ 4 ] { new Map(10), new Map(20), new Map(30), new Map(40)}; arr [ 2 ].Size = 0;
But when using List, it doesn't compile:
List<Map> list = new List<Map> ( ) { new Map(10), new Map(20), new Map(30), new Map(40)}; list [ 2 ].Size = 0;
Why?
The C# compiler will give you the following error:
Cannot modify the return value of 'System.Collections.Generic.List.this[int]' because it is not a variable
The reason is that structs are value types so when you access a list element you will in fact access an intermediate copy of the element which has been returned by the indexer of the list.
From MSDN:
Error Message
Cannot modify the return value of 'expression' because it is not a variable
An attempt was made to modify a value type that was the result of an intermediate expression. Because the value is not persisted, the value will be unchanged.
To resolve this error, store the result of the expression in an intermediate value, or use a reference type for the intermediate expression.
Solutions:
List<Map> list = new List<Map>() { new Map(10), new Map(20), new Map(30), new Map(40) }; Map map = list[2]; map.Size = 42; list[2] = map;
Because it is a struct
, when using the List<T>, you're are creating copies.
When using a struct, it is better to make them immutable. This will avoids effects like this.
When using an array, you have direct access to the memory structures. Using the List<T>.get_Item you work on a return value, that is, a copy of the structure.
If it was a class, you would get a copy of a pointer to the class, but you would not notice this, since pointers are hidden in C#.
Also using the List<T>.ToArray does not solve it, because it will create a copy of the internal array, and return this.
And this is not the only place where you will get effects like this when using a struct.
The solution provided by Divo is a very good workaround. But you have to remember to work this way, not only when using the List<T> but everywhere you want to change a field inside the struct.
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