简体   繁体   中英

Why can we assign readonly IList collection with collection initializer?

The readonly Children property of StackLayout is of type IList<View> . I got surprised knowing Children can be assigned with collection initializer as shown in the following code snippet (inspired by an example given by Xamarin.Forms documentation ):

public MainPage()
{   
    StackLayout sl = new StackLayout
    {
        Children =
        {
            new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
        }
    };
}

Question

Why can it be assigned while it is a readonly property?

Next, I made a counter example as follows. Here the compiler complains that Children is a readonly property. It is understandable but the previous one is not. Could you tell me why?

public MainPage()
{                       
    IList<Label> labels = new List<Label>
    {
        new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
    };

    StackLayout sl = new StackLayout
    {
        Children = labels
    };
}

A collection-initializer just fills the collection by calling its Add -method. It does not create it. Thus the following

Children = { ... }

is just syntactic sugar for this:

Children.Add(...);
Children.Add(...);    
Children.Add(...);
...

You see this assumes there already is a collection on which you can call Add , otherwise you´d get a NullReferenceException. So the code of the StackLayou is probably similar to this:

class StackLayout 
{
    public readonly WhataverCollectionType Children = new WhateverCollectionType();
}

As WhateverCollectionType implements IEnumerable and has an Add -method, you may use a collection-initializer.

Just an asside: Actually it´s bit different, the StackLayout derives from Layout which initializes the field to some ElementCollection , which implements IEnumerable .

Your second example clearly reassigns a list to Children , which is not allowed ony a readonly -field. You could also write this, which makes this a bit easier to understand:

StackLayout sl = new StackLayout
{
    Children = new List<Label> { ... }
};

This is compiled to something similar to this:

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

Because in first case you are constructing it(creating), not assigning. In second case you are trying to modify it

In the example from the documentation there is no new instance of List<Label> created and assigned to the Children property. The following code just calls the method Add() on the existing instance.

 Children =
 {
    new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
 }

basically it just calls

sl.Children.Add(new Label{Text="Start",HorizontalOptions=LayoutOptions.Start});

This on the other hand would also fail cause it would assign a new instance to the Children property:

 Children = new List<Label>
 {
    new Label{Text="Start",HorizontalOptions=LayoutOptions.Start}
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM