Reputation: 338
using System;
using System.Collections.Generic;
class Parent
{
public Child Child { get; set; }
}
class Child
{
public List<string> Strings { get; set; }
}
static class Program
{
static void Main() {
// bad object initialization
var parent = new Parent() {
Child = {
Strings = { "hello", "world" }
}
};
}
}
The above program compiles fine, but crashes at runtime with Object reference not set to an instance of the object.
If you notice in the above snippet, I have omitted new while initializing the child properties.
Obviously the correct way to initialize is:
var parent = new Parent() {
Child = new Child() {
Strings = new List<string> { "hello", "world" }
}
};
My question is why does the C# compiler not complain when it sees the first construct?
Why is the broken initialization valid syntax?
var parent = new Parent() {
Child = {
Strings = { "hello", "world" }
}
};
Upvotes: 24
Views: 5738
Reputation: 2986
Note that this syntax can cause some unexpected results and hard-to-spot errors:
class Test
{
public List<int> Ids { get; set; } = new List<int> { 1, 2 };
}
var test = new Test { Ids = { 1, 3 } };
foreach (var n in test)
{
Console.WriteLine(n);
}
You might expect the output to be 1,3, but instead it is:
1
2
1
3
Upvotes: 0
Reputation: 78183
You seem to misunderstand what the collection initializer does.
It is a mere syntactic sugar that converts the list in the braces into a series of calls to Add()
method that must be defined on the collection object being initialized.
Your = { "hello", "world" }
is therefore has the same effect as
.Add("hello");
.Add("world");
Obviously this will fail with a NullReferenceException if the collection is not created.
Upvotes: 7
Reputation: 700552
There is nothing wrong with the initialisation, but it's trying to initialise objects that doesn't exist.
If the classes have constructors that create the objects, the initialisation works:
class Parent {
public Child Child { get; set; }
public Parent() {
Child = new Child();
}
}
class Child {
public List<string> Strings { get; set; }
public Child() {
Strings = new List<string>();
}
}
Upvotes: 12
Reputation: 615
The second syntax is valid for readonly properties. If you change the code to initialise the Child and Strings properties in the respective constructors, the syntax works.
class Parent
{
public Parent()
{
Child = new Child();
}
public Child Child { get; private set; }
}
class Child
{
public Child()
{
Strings = new List<string>();
}
public List<string> Strings { get; private set; }
}
static class Program
{
static void Main()
{
// works fine now
var parent = new Parent
{
Child =
{
Strings = { "hello", "world" }
}
};
}
}
Upvotes: 4
Reputation: 44449
It's not broken syntax, it's you who uses an object initializer on a property that's simply not instantiated. What you wrote can be expanded to
var parent = new Parent();
parent.Child.Strings = new List<string> { "hello", "world" };
Which throws the NullReferenceException
: you're trying to assign the property Strings
contained by the property Child
while Child
is still null
.
Using a constructor to instantiate Child
first, takes care of this.
Upvotes: 18