Under the premise that these initialization statements compile
List<int> l = new List<int> { 1, 2, 3 };
Dictionary<int, int> d = new Dictionary<int, int> { [1] = 11, [2] = 22 };
Foo f = new Foo { Bar = new List<int>() };
and this will not
List<int> l = { 1, 2, 3 };
Dictionary<int, int> d = { [1] = 11, [2] = 22 };
Foo f = { Bar = new List<int>() };
I have a question about nested initializations. Given the following class
public class Foo {
public List<int> Bar { get; set; } = new List<int>();
public Dictionary<int, Foo> Baz { get; set; } = new Dictionary<int, Foo>();
}
I discovered by accident that you could actually do this:
Foo f = new Foo {
Bar = { 1, 2, 3 },
Baz = {
[1] = {
Bar = { 4, 5, 6 }
}
}
};
While it does compile it throws a KeyNotFoundException
. So I changed the properties to
public List<int> Bar { get; set; } = new List<int> { 4, 5, 6 };
public Dictionary<int, Foo> Baz { get; set; }
= new Dictionary<int, Foo> { [1] = new Foo { Bar = new List<int>() { 1, 2, 3 } } };
assuming that this is some unusual notation for replacing existing members. Now the initialization throws a StackOverflowException
.
So my question is, why does the expression even compile? What is it supposed to do? I feel like I must be missing something really obvious.
So my question is, why does the expression even compile?
It's an object initializer with a collection initializer value. From the C# specification section 7.6.10.2:
A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the field or property, the elements given in the initializer are added to the collection referenced by the field or property.
So your code code is roughly equivalent to:
Foo tmp = new Foo();
tmp.Bar.Add(1);
tmp.Bar.Add(2);
tmp.Bar.Add(3);
tmp.Baz[1].Bar.Add(4); // This will throw KeyNotFoundException if Baz is empty
tmp.Baz[1].Bar.Add(5);
tmp.Baz[1].Bar.Add(6);
Foo f = tmp;
Your initialization version will throw a StackOverflowException
because the initializer for Foo
needs to create a new instance of Foo
, which needs to create a new instance of Foo
etc.
See more on this question at Stackoverflow