I saw NRE when using array initializer in object initializer and there was a update and https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6#extension-add-methods-in-collection-initializers but still I cannot understand.
var arr = new int[] { 1, 2, 3 }
generate IL code using stelem
.
But int[] arr = { 1, 2, 3 }
generate IL code using RuntimeHelpers.InitializeArray
. I think it is using Array.Add
extension method which was talk in that answer.
But in object initializer, all array initializer generate second code. An example,
new A() {
arr = new int[] { 1, 2, 3 }
}
Array arr
is created using RuntimeHelpers.InitializingArray
too. Then, doesn't it mean there isn't any problem in next code?
new A() {
arr = { 1, 2, 3 } // Compiler error!
}
Not like old version of c# compiler, it makes compiler error saying system.array does not contain a definition for Add
. What's happening?
EDIT
I thought just syntax without new []
makes differences but actually more than three elements makes different IL code.
The second syntax ( { arr = {... } }
) is syntax sugar for sequence of value.arr.Add(.)
- presumably value.arr
is not initialized in your constructor and hence NRE.
Assuming A
is:
class A {
public int[] arr {get;set}
}
then
var x = new A() {
arr = { 1, 2, 3 } // Compiler error!
};
is the same as
var x = new A(); // note x.arr is default null here
x.arr.Add(1); // NRE is arr is list, can't compile for int[]
x.arr.Add(2);
x.arr.Add(3);
Fix: use list, there is no reasonable way to add elements to an array.
If using some other type that does not have .Add
- implement extension method that is visible to that code.
Why version with new
works:
var x = new A() {
arr = new int[] { 1, 2, 3 }
};
is equivalent* of
var x = new A();
x.arr = new int[] { 1, 2, 3 };
Note that in array initializer you can use both syntaxes to the same effect, but not in array field's initializers (All possible C# array initialization syntaxes)
int[] x = { 10, 20, 30 }; // valid, same as int[] x = new int[]{ 10, 20, 30 };
while new A { arr = { 10, 20, 30} }
is not the same as new A { arr = new int[3]{ 10, 20, 30} }
*It is really a bit more complicated to satisfy rules when change must be observable - see Eric Lippert's comment below