Combining List initializer and object initializer
Asked Answered
P

3

19

Is is possible to combine a List initializer and object initializer at the same time? Given the following class definition:

class MyList : List<int>
{
    public string Text { get; set; }
}

// we can do this
var obj1 = new MyList() { Text="Hello" };

// we can also do that
var obj2 = new MyList() { 1, 2, 3 };

// but this one doesn't compile
//var obj3 = new MyList() { Text="Hello", 1, 2, 3 };

Is this by design or is it just a bug or missing feature of the c# compiler?

Platitudinize answered 6/6, 2011 at 15:16 Comment(0)
F
29

No, looking at the definitions from section 7.6.10 of the C# spec, an object-or-collection-initializer expression is either an object-initializer or a collection-initializer.

An object-initializer is composed of multiple member-initializers, each of which is of the form initializer = initializer-value whereas a collection-initializer is composed of multiple element-initializers, each of which is a non-assigment-expression.

So it looks like it's by design - possibly for the sake of simplicity. I can't say I've ever wanted to do this, to be honest. (I usually wouldn't derive from List<int> to start with - I'd compose it instead.) I would really hate to see:

var obj3 = new MyList { 1, 2, Text = "Hello", 3, 4 };

EDIT: If you really, really want to enable this, you could put this in the class:

class MyList : List<int>
{
    public string Text { get; set; }
    public MyList Values { get { return this; } }
}

at which point you could write:

var obj3 = new MyList { Text = "Hello", Values = { 1, 2, 3, 4 } };
Furst answered 6/6, 2011 at 15:20 Comment(7)
The spec should force the object initializer part and the list initializer part one after another and not interleaved :)Platitudinize
@Tejs: No you wouldn't. It's using an embedded collection initializer.Furst
Am I missing something here? That statement is equivalent to var x = new MyList(); x.Text = "Hello"; x.Values = new List<int> { 1, 2, 3, 4 }? Seems like you would need a set.Baumann
@Tejs: No it's not... where do you see it creating a new List<int>? It's (mostly) like saying var x = new MyList(); x.Text = "Hello"; x.Values.Add(1); x.Values.Add(2); ... Try it :)Furst
Ah, my bad. I forget that collection initializers just call the Add method.Baumann
@Jon Skeet: funny idea making a property returning itself :)Platitudinize
More fun from @Jon: msmvps.com/blogs/jon_skeet/archive/2013/02/14/…Sherry
B
4

No, it's a not a bug. It is by design of the language.

When you write

var obj1 = new MyList() { Text="Hello" };

this is effectively translated by the compiler to

MyList temp = new MyList();
temp.Text = "Hello";
MyList obj = temp;

When you write

var obj2 = new MyList() { 1, 2, 3 };

this is effectively translated by the compiler to

MyList temp = new MyList();
temp.Add(1);
temp.Add(2);
temp.Add(3);
MyList obj2 = temp;

Note that in the first case you are using an object initializer, but in the second case you are using a collection initializer. There is no such thing as an object-and-collection intializer. You are either initializing the properties of your object, or you are initializing the collection. You can not do both, this is by design.

Also, you shouldn't derive from List<T>. See: Inheriting List<T> to implement collections a bad idea?

Beaty answered 6/6, 2011 at 15:20 Comment(1)
I know how it is translated. I still see no reason why we can't combine the first one with the latter.Platitudinize
B
2

If you want to get something like this functionality, consider making a constructor argument:

var x = new CustomList("Hello World") { 1, 2, 3 }
Baumann answered 6/6, 2011 at 15:30 Comment(1)
But in the case where I have lots of arguments but want to set only a few of them in most cases this won't be the best solutionPlatitudinize

© 2022 - 2024 — McMap. All rights reserved.