Search code examples
c#propertiesclrgetter-setter

Why does collection initializer work with getter-only property?


It is very unpredictable result of code for me.

I did not expect this code to produce such a result.

So, I read Jeffrey Richter's book (clr ia c#) and there is a example with this code.

internal class ClassRoom
{
    private List<String> _students = new List<string>();
    public List<String> Students { get { return _students; } }
}

ClassRoom classRoom = new ClassRoom
{
    Students = {"Mike", "Johny", "Vlad", "Stas"}
};

foreach (var some in classRoom.Students)
{
    Console.WriteLine(some);
}

And, as some of you can suggest we can see in console four names. So, my question is:

How do we get our names, if they are going to get in Students and respectively in _students, that were not assigned because of nonexistence of Students setter.

__________EDIT_1_______________

I read your answers, and thank you for those.

But, you know, it is kind of misunderstanding... I really can't figure it out.

When I Initialize Students, I initialize _students ?

And what not less important, when I take variable from IEnumerable(some), I am take variable from Students ? I think not.

I can't understand, WHERE exactly I assign variables(INITALIZE) _students collections ?

Thank you for help me to figure it out!


Solution

  • These other answers are almost right. Let's go through it and actually get it all right.

    Why does a collection initializer work with a getter-only property?

    Because the property value is not changed. The contents of the collection that the property refers to is what is changed.

    Think of a property as a bucket. You can't change which bucket the property refers to, but you can change the contents of the bucket.

    How do we get our names, if they are going to get in Students and respectively in _students, that were not assigned because of nonexistence of Students setter.

    The Students property is never assigned, at all. How could it be? It has no setter.

    The names are added to the collection referred to by the Students getter.

    When I Initialize Students, I initialize _students ?

    No. The initialization of _students is the line which assigns a value to _students.

    The collection initializer adds values to an existing collection. The variable _students has already been initialized.

    when I take variable from IEnumerable(some), I am take variable from Students ?

    You don't take a variable from anything. You take values. Variables are not values; variables contain values. Don't confuse the storage with the value stored.

    I can't understand, WHERE exactly I assign variables(INITALIZE) _students collections ?

    The _students variable is initialized in the line that initializes _students. The contents of the collection are initialized in the line that has the contents.

    Perhaps it will help to list everything that happens in exactly the order it happens:

    • a new Classroom object is created; the _students field is null; a reference to the object is produced.
    • a new empty list is created; a reference to the list is copied into the _students field of the newly-created Classroom object.
    • the Students getter is called on the reference to the new Classroom object. It returns the contents of _students, which is a reference to an empty list.
    • four items are added to that list
    • the reference to the Classroom object is copied to the classroom variable.

    Or, in code, this is equivalent to:

    c = create a Classroom
    c._students = null
    l1 = create a List<string>
    c._students = l1
    l2 = c.Students -- which returns c._students
    l2.Add("...")  -- four times
    classRoom = c
    

    See, there is never a setter of Students called. There doesn't need to be. All it does is gets the reference contained in _students, which already has been initialized by the field initializer.