c#中只读属性的对象初始值设定项
Object initializer for readonly properties in c#
如果你有 class:
class Foo {
Bar Bar { get; } = new Bar();
}
class Bar {
string Prop {get; set; }
}
您可以使用像这样的对象初始化:
var foo = new Foo {
Bar = { Prop = "Hello World!" }
}
如果你有class
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 }) }
}
但是,上面的代码不能编译:
cannot assigne IEnumerable to Bar
我不会写:
var foo = new Foo2 {
Bars = items.Select(s => new Bar { Prop = s })
}
属性 Bars 是只读的。
可以存档吗?
Bars = { ... }
不做作业。相反,它会为初始化程序中的每个项目调用 Add
。这就是它不起作用的原因。
这就是 Bars = items.Select(s => new Bar { Prop = s })
给出相同错误的原因:它是一个赋值,而不是要添加的列表。
除了使用构造函数传入值,或者在构造函数具有 运行.
之后使用常规 Add
或 AddRange
语句之外,别无选择
如果您阅读 实际 编译器错误 (and the docs for collection initializers),您会发现集合初始值设定项是 Add()
调用的语法糖:
CS1950: The best overloaded collection initalizer method System.Collections.Generic.ICollection<Bar>.Add(Bar)
has some invalid arguments
CS1503: Argument #1
cannot convert System.Collections.Generic.IEnumerable<Bar>
expression to type 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" } }
};
但这太恶心了。
如果你有 class:
class Foo {
Bar Bar { get; } = new Bar();
}
class Bar {
string Prop {get; set; }
}
您可以使用像这样的对象初始化:
var foo = new Foo {
Bar = { Prop = "Hello World!" }
}
如果你有class
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 }) }
}
但是,上面的代码不能编译:
cannot assigne IEnumerable to Bar
我不会写:
var foo = new Foo2 {
Bars = items.Select(s => new Bar { Prop = s })
}
属性 Bars 是只读的。
可以存档吗?
Bars = { ... }
不做作业。相反,它会为初始化程序中的每个项目调用 Add
。这就是它不起作用的原因。
这就是 Bars = items.Select(s => new Bar { Prop = s })
给出相同错误的原因:它是一个赋值,而不是要添加的列表。
除了使用构造函数传入值,或者在构造函数具有 运行.
之后使用常规Add
或 AddRange
语句之外,别无选择
如果您阅读 实际 编译器错误 (and the docs for collection initializers),您会发现集合初始值设定项是 Add()
调用的语法糖:
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
因此语法 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" } }
};
但这太恶心了。