4

I'm observing some strange behavior (tested in VS2013) when using array initializer in the following case:

    class A
    {
        public List<int> Items { get; set; }
    }

    void Main(string[] args)
    {
        // (1) it compiles, but failing with NRE in runtime
        var a = new A { Items = { 1, 2, 3 } };

        // (2) it does not compile, as expected
        List<int> b = { 1, 2, 3 };
    }

Actually I would expect a compiler error in the case (1), the same that I have in case (2): Can only use array initializer expressions to assign to array types. Try using a new expression instead. But the case (1) compiles without any problem and expectable fails with NullReferenceException when running. Can someone explain why compiler allows the case (1)?

ie.
  • 5,982
  • 1
  • 29
  • 44

1 Answers1

1

Here is the relevent quote from the C# spec (version 5, 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. The field or property must be of a collection type that satisfies the requirements specified in ยง7.6.10.3.

So because you're using a collection initializer inside an object initializer, the behaviour is different, and this code:

var a = new A { Items = { 1, 2, 3 } };

Compiles down to something like this (You can verify this by looking at the IL):

var a = new A();
a.Items.Add(1);
a.Items.Add(2);
a.Items.Add(3);

This of course throws a NullReferenceException because Items is null.

You can fix the crash by adding a constructor to class A:

class A
{
    public List<int> Items { get; set; }
    public A() { Items = new List<int>(); }
}
Blorgbeard
  • 101,031
  • 48
  • 228
  • 272