如果您有课程:
class Foo {
Bar Bar { get; } = new Bar();
}
class Bar {
string Prop {get; set; }
}
您可以使用对象初始化,例如:
var foo = new Foo {
Bar = { Prop = "Hello World!" }
}
如果您有课程
class Foo2 {
ICollection<Bar> Bars { get; } = new List<Bar>();
}
您可以写
var foo = new Foo2 {
Bars = {
new Bar { Prop = "Hello" },
new Bar { Prop = "World" }
}
}
但是,我想写些类似的东西
var items = new [] {"Hello", "World"};
var foo = new Foo2 {
Bars = { items.Select(s => new Bar { Prop = s }) }
}
但是,上面的代码无法与以下代码一起编译:
无法将IEnumerable分配给Bar
我不能写:
var foo = new Foo2 {
Bars = items.Select(s => new Bar { Prop = s })
}
属性栏为只读。
可以存档吗?
答案 0 :(得分:2)
Bars = { ... }
不执行作业。相反,它为初始化程序中的每个项目调用Add
。这就是为什么它不起作用的原因。
这就是Bars = items.Select(s => new Bar { Prop = s })
给出相同错误的原因:这是一个分配,而不是要添加的列表。
除了使用构造函数传递值或在构造函数运行后使用常规Add
或AddRange
语句外,没有其他选择。
答案 1 :(得分:2)
如果您阅读了 actual 编译器错误(and the docs for collection initializers),则会发现集合初始化程序是Add()
调用的语法上的甜言蜜语:
CS1950:最佳的重载集合initalizer方法
System.Collections.Generic.ICollection<Bar>.Add(Bar)
具有一些无效的参数CS1503:参数
#1
无法将System.Collections.Generic.IEnumerable<Bar>
表达式转换为类型Bar
因此语法SomeCollection = { someItem }
将被编译为SomeCollection.Add(someItem)
。而且您无法将IEnumerable<Bar>
添加到Bar
的集合中。
您需要手动添加所有项目:
foreach (bar in items.Select(s => new Bar { Prop = s }))
{
foo.Bars.Add(bar);
}
或者,鉴于较短的代码是您的目标,请在Foo2
的构造函数中执行相同的操作:
public class Foo2
{
public ICollection<Bar> Bars { get; }
public Foo2() : this(Enumerable.Empty<Bar>()) { }
public Foo2(IEnumerable<Bar> bars)
{
Bars = new List<Bar>(bars);
}
}
然后您可以像这样初始化Foo2:
var foo = new Foo2(items.Select(...));
对于@JeroenMostert假设的集合初始化器语法的有趣滥用,您可以使用扩展方法:
public static class ICollectionExtensions
{
public static void Add<T>(this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
{
collection.Add(item);
}
}
}
哪个允许:
public class Foo
{
public ICollection<string> Bar { get; } = new List<string>();
}
var foo = new Foo
{
Bar = { new [] { "foo", "bar", "baz" } }
};
但这太讨厌了。