0

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
    };
}
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165
  • 1
    Auto properties with only `get` defined can be changed within constructor. On first case you're creating the object – Kevin Kouketsu Sep 11 '19 at 13:48
  • The documentation of [readonly keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly) may help you understand better. – Anoop R Desai Sep 11 '19 at 14:00
  • @KevinKouketsu: Yes I know that "Auto properties with only get defined can be changed within constructor. ". But I am not defining a constructor here, so it is not relevant. – Second Person Shooter Sep 11 '19 at 14:55
  • @WellHarassedProgrammer I was a little brief, i'm sorry about that. Like HimBromBeere said, you're not reassigning on first case. My bad! – Kevin Kouketsu Sep 11 '19 at 15:43

3 Answers3

5

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
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
1

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

Djuro
  • 384
  • 2
  • 9
0

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}
 }
Andreas
  • 224
  • 1
  • 7