[英]Object initializer for readonly properties in c#
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 无法将IEnumerable分配给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: 如果您阅读了实际的编译器错误( 以及集合初始值设定项的文档 ),您会发现集合初始值设定项是Add()
调用的语法语法糖:
CS1950: The best overloaded collection initalizer method
System.Collections.Generic.ICollection<Bar>.Add(Bar)
has some invalid arguments CS1950:最佳重载的集合初始化方法System.Collections.Generic.ICollection<Bar>.Add(Bar)
有一些无效的参数CS1503: Argument
#1
cannot convertSystem.Collections.Generic.IEnumerable<Bar>
expression to typeBar
CS1503:参数#1
不能转换System.Collections.Generic.IEnumerable<Bar>
表达式输入Bar
So the syntax SomeCollection = { someItem }
will be compiled to SomeCollection.Add(someItem)
. 因此语法SomeCollection = { someItem }
将被编译为SomeCollection.Add(someItem)
。 And you can't add IEnumerable<Bar>
to a collection of Bar
s. 而且您不能将IEnumerable<Bar>
添加到Bar
的集合中。
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: 或者,鉴于较短的代码是您的目标,请在Foo2
的构造函数中执行相同的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);
}
}
Then you can initialize Foo2 like this: 然后,您可以像这样初始化Foo2:
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: 对于@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);
}
}
}
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. 但这太讨厌了。
Bars = { ... }
Doesn't do an assignment. Bars = { ... }
不做作业。 Instead it calls Add
for every item in the initializer. 而是为初始化程序中的每个项目调用Add
。 That is why it doesn't work. 这就是为什么它不起作用。
That is why Bars = items.Select(s => new Bar { Prop = s })
gives the same error: it is an assignment, not a list to add. 这就是Bars = items.Select(s => new Bar { Prop = s })
给出相同错误的原因:这是一个分配,而不是要添加的列表。
There is no option other that using a constructor to pass in the values, or use regular Add
or AddRange
statements after the constructor has ran. 除了使用构造函数传递值,或者在构造函数运行后使用常规的Add
或AddRange
语句外,没有其他选择。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.