If you have the class:
class Foo {
Bar Bar { get; } = new Bar();
}
class Bar {
string Prop {get; set; }
}
You can use a object initialise like:
var foo = new Foo {
Bar = { Prop = "Hello World!" }
}
If you have a class
class Foo2 {
ICollection<Bar> Bars { get; } = new List<Bar>();
}
You can write
var foo = new Foo2 {
Bars = {
new Bar { Prop = "Hello" },
new Bar { Prop = "World" }
}
}
but, I would like to write something like
var items = new [] {"Hello", "World"};
var foo = new Foo2 {
Bars = { items.Select(s => new Bar { Prop = s }) }
}
However, the code above does not compile with:
cannot assigne IEnumerable to Bar
I cannot write:
var foo = new Foo2 {
Bars = items.Select(s => new Bar { Prop = s })
}
Property Bars is readonly.
Can this be archived?
If you read the actual compiler errors (and the docs for collection initializers), you'll find that collection initializers are merly syntactic sugar for Add()
calls:
CS1950: The best overloaded collection initalizer method
System.Collections.Generic.ICollection<Bar>.Add(Bar)
has some invalid argumentsCS1503: Argument
#1
cannot convertSystem.Collections.Generic.IEnumerable<Bar>
expression to typeBar
So the syntax SomeCollection = { someItem }
will be compiled to SomeCollection.Add(someItem)
. And you can't add IEnumerable<Bar>
to a collection of Bar
s.
You need to manually add all items:
foreach (bar in items.Select(s => new Bar { Prop = s }))
{
foo.Bars.Add(bar);
}
Or, given shorter code is your goal, do the same in Foo2
's constructor:
public class Foo2
{
public ICollection<Bar> Bars { get; }
public Foo2() : this(Enumerable.Empty<Bar>()) { }
public Foo2(IEnumerable<Bar> bars)
{
Bars = new List<Bar>(bars);
}
}
Then you can initialize Foo2 like this:
var foo = new Foo2(items.Select(...));
For a funny abuse of the collection initializer syntax as supposed by @JeroenMostert, you could use an extension method:
public static class ICollectionExtensions
{
public static void Add<T>(this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
{
collection.Add(item);
}
}
}
Which allows this:
public class Foo
{
public ICollection<string> Bar { get; } = new List<string>();
}
var foo = new Foo
{
Bar = { new [] { "foo", "bar", "baz" } }
};
But that's just nasty.