4

When I run this code, it doesn't initialize ThisIsAList to an empty collection as I was expecting... instead ThisIsAList was null.

void Main()
{
    var thing = new Thing
    {
        ThisIsAList = {}
    };

    Console.WriteLine(thing.ThisIsAList == null); // prints "True"
}

public class Thing
{
    public List<string> ThisIsAList { get; set; }
}

Why isn't this a compile error? Why is the result null?


I was wondering if maybe there was an implicit conversion going on here, but the following attempts produced compile errors:

thing.ThisIsAList = Enumerable.Empty<string>().ToArray();
List<int> integers = { 0, 1, 2, 3 };

According to MSDN documenation on collection initializers, it sounds like a collection initializer basically just handles calling Add() for you. So I looked for possible overloads to List.Add, but didn't find anything that I think would apply.

Can someone explain what's going on here from the C# spec?

Jeff B
  • 8,572
  • 17
  • 61
  • 140
  • 1
    Servy has the explanation below, but what you want to be doin is: `new List {}` – Asad Saeeduddin May 06 '15 at 18:32
  • Or is `new List()` better? Maybe it doesn't matter. I thought I saw a question today about which of the two options was better, but I can't for the life of me find it now. – Jeff B May 06 '15 at 18:42

1 Answers1

7

In section 7.6.10.2 of the C# 5.0 specs:

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. The field or property must be of a collection type that satisfies the requirements specified in §7.6.10.3.

(emphasis mine)

So since your collection initializer is nested inside of another object/collection initializer the behavior is that it resolves the member it is initialzing to a value, and then adds the relevant items. In this case, the property is null, so that null value is resolved, and all zero items in your initializer are added. If you actually tried to add an item, it'd throw a NRE since you'd be trying to add an item to a null object.

Servy
  • 202,030
  • 26
  • 332
  • 449