1

I noticed strange behaviour when initializing collection property.

Consider:

class X
{
    public IList<int> Ints { get; set; }
}

I can initialize Ints like that:

var theObject = new X
{
    Ints = { 12, 3, 4, 5, 6 }
};

But I cannot do that:

var x = new X();

x.Ints = { 12, 3, 4, 5, 6 }

Any ideas why? It seems pretty unintuitive.

Pawel
  • 525
  • 3
  • 16

2 Answers2

5

new X ... is the start of an object creation expression. In this kind of expressions, an object or collection initializer is allowed:

object_creation_expression
    : 'new' type '(' argument_list? ')' object_or_collection_initializer?
    | 'new' type object_or_collection_initializer  // <--- here!
    ;

object_or_collection_initializer
    : object_initializer
    | collection_initializer
    ;

In your code, you have an object initialiser { Ints = ... }. Inside that, there is another collection initialiser { 12, 3, 4, 5, 6 }. This is allowed, as per the grammar:

object_initializer
    : '{' member_initializer_list? '}'
    | '{' member_initializer_list ',' '}'
    ;

member_initializer_list
    : member_initializer (',' member_initializer)*
    ;

member_initializer
    : initializer_target '=' initializer_value
    ;

initializer_target
    : identifier
    | '[' argument_list ']'
    ;

initializer_value
    : expression
    | object_or_collection_initializer // <---- here!
    ;

An initializer_value can either be an expression, or another object_or_collection_initializer. This also implies that, though they may look like it, object_or_collection_initializer, i.e. things like { 12, 3, 4, 5, 6 }, are not a kind of expression.

On the other hand, assignments don't allow this. Assignments only allow an expression to be on the right hand side:

assignment
    : unary_expression assignment_operator expression
    ;
Sweeper
  • 213,210
  • 22
  • 193
  • 313
0

As pointed out in the comments, this is an example of a collection initializer.

It's really syntactic sugar for something along the lines of the following:

var theObject = new X();
theObject.Items.Add(12);
theObject.Items.Add(3);
theObject.Items.Add(4);
theObject.Items.Add(5);
theObject.Items.Add(6);

Anything that fits the right 'shape' can be initialized this way. (Essentialy it's looking for an Add(...) method matching the right signature of your types.) You can even use this to initialize Dictionary collections.

Alphacat
  • 323
  • 2
  • 8