[英]Why can we assign readonly IList collection with collection initializer?
StackLayout
的readonly
Children
属性的类型为IList<View>
。 我惊讶地得知,可以为Children
分配集合初始值设定项,如以下代码片段所示(受Xamarin.Forms文档给出的示例的启发):
public MainPage()
{
StackLayout sl = new StackLayout
{
Children =
{
new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
}
};
}
为什么当它是只读属性时才能分配它?
接下来,我做了一个反例如下。 在这里,编译器抱怨Children
是一个只读属性。 这是可以理解的,但前一个不是。 你能告诉我为什么吗?
public MainPage()
{
IList<Label> labels = new List<Label>
{
new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
};
StackLayout sl = new StackLayout
{
Children = labels
};
}
集合初始化器只是通过调用其Add
方法来填充集合。 它不会创建它。 因此以下
Children = { ... }
只是语法糖:
Children.Add(...);
Children.Add(...);
Children.Add(...);
...
您将看到这是假设已经存在一个可以调用Add
的集合,否则您将获得NullReferenceException.
因此, StackLayou
的代码可能与此类似:
class StackLayout
{
public readonly WhataverCollectionType Children = new WhateverCollectionType();
}
由于WhateverCollectionType
实现IEnumerable
并具有Add
方法,因此您可以使用collection-initializer。
StackLayout
:实际上有点不同, StackLayout
派生自Layout
,该Layout
将字段初始化为一些实现IEnumerable
ElementCollection
。
您的第二个示例清楚地将列表重新分配给Children
,仅在readonly
字段中不允许该列表。 您也可以编写此代码,这使它更容易理解:
StackLayout sl = new StackLayout
{
Children = new List<Label> { ... }
};
编译成类似于以下内容:
StackLayout sl = new StackLayout(); // will also assign Children to a new list
var list = new List<Label>();
list.Add(...);
list.Add(...);
...
sl.Children = list; // this re-assigns the member which is not allowed as it is readonly
因为在第一种情况下,您正在构造(创建)它,而不是分配。 在第二种情况下,您正在尝试对其进行修改
在文档的示例中,没有创建List<Label>
并将其分配给Children
属性的新实例。 以下代码仅在现有实例上调用方法Add()
。
Children =
{
new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
}
基本上它只是调用
sl.Children.Add(new Label{Text="Start",HorizontalOptions=LayoutOptions.Start});
另一方面,这也会失败,因为它将为Children
属性分配一个新实例:
Children = new List<Label>
{
new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.