Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializer syntax for list properties

Tags:

c#

I witnessed something strange when initializing a class with a List as a property. When doing this

var stuff = new Stuff(){list = {1, 2, 3} };

It compiles, and crashes saying that list is null. So, adding this to Stuff's constructor:

public Stuff(){
    list = new List<int>();
}

List is now initialized to contain {1, 2, 3} which seems to make some sense. But then, changing the constructor to

public Stuff(){
    list = new List<int>(){1, 2, 3};
}

And initializing like so

var stuff = new Stuff(){list = {4, 5, 6} };

list is initialized to contain {1, 2, 3, 4, 5, 6} leaving me rather confused.

It seems like this either shouldn't compile, or shouldn't behave this way. What exactly is going on here?

like image 478
Eric B Avatar asked Oct 30 '13 21:10

Eric B


2 Answers

It seems like this either shouldn't compile, or shouldn't behave this way. What exactly is going on here?

Collection initializers work by calling the .Add method on each item passed into the initializer. This adds them to the items you pre-populate within your constructor.

This is explained in the documentation for Collection Initializers:

Collection initializers let you specify one or more element initializers when you initialize a collection class that implements IEnumerable. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer you do not have to specify multiple calls to the Add method of the class in your source code; the compiler adds the calls.

This means the compiler turns your second call into something similar to:

var temp = new Stuff();
temp.list.Add(4);
temp.list.Add(5);
temp.list.Add(6);
Stuff stuff = temp;

As you can see, the stuff variable will call the constructor normally (which adds 1, 2, and 3), then add the other items, resulting in what you see.

like image 166
Reed Copsey Avatar answered Sep 18 '22 16:09

Reed Copsey


You are initializing list using a collection initializer. This way this works is given in the documentation:

Collection initializers let you specify one or more element initializers when you initialize a collection class that implements IEnumerable. The element initializers can be a simple value, an expression or an object initializer. By using a collection initializer you do not have to specify multiple calls to the Add method of the class in your source code; the compiler adds the calls.

In other words, this:

var stuff = new Stuff(){list = {1, 2, 3} };

is a shorthand way of writing this:

var temp = new Stuff();
temp.list.Add(1);
temp.list.Add(2);
temp.list.Add(3);
stuff = temp;

It's easy to see how this would cause a NullReferenceException if list is null and how it appends to the existing items in the list, if any.

like image 23
Jon Avatar answered Sep 19 '22 16:09

Jon