Почему я могу использовать инициализатор коллекции с доступом из частного набора из другого класса?

Рассмотрим следующий код:

public sealed class Order
{
    public Order()
    {
        Items = new List<OrderItem>();
    }

    public List<OrderItem> Items { get; private set; }
}

public sealed class OrderItem
{
}

и здесь Order инициализация в другом классе.

var order = new Order
{
    Items =
    {
        new OrderItem(),
        new OrderItem()
    }
};

Не могли бы вы объяснить, почему это работает? Как вы видите, свойство Order имеет свойство private set, поэтому я думал, что установить его значение невозможно.

Ответ 1

Краткий ответ:

Он работает через инициализатор коллекции, который вызывает Add для добавления элементов

Длинный ответ:

Взаимодействие coding encodingly С# 3.0, объект, реализующий IEnumerable и имеющий подходящий метод Add, может быть инициализирован методом Add.

Items имеет public get accessor и Items он a List<T>, который реализует IEnumerable и имеет Add. Вот как компилятор видит ваш код

var order = new Order();
order.Items.Add(new OrderItem());
order.Items.Add(new OrderItem());

Обратите внимание, что компилятор не использует информацию, которую List реализует IEnumerable, здесь доказательство, исключение не будет выбрано

public sealed class Order
{
    public Order()
    {
        Items = new MyCollection();
    }

    public MyCollection Items { get; private set; }
}

public sealed class OrderItem
{
}

public class MyCollection : IEnumerable
{
    private readonly List<OrderItem> _items = new List<OrderItem>();

    public void Add(OrderItem item)
    {
        _items.Add(item);
    }

    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

из Спецификация языка С#

Объект коллекции, к которому применяется инициализатор коллекции должен быть типа, который реализует System.Collections.IEnumerable или возникает ошибка времени компиляции. Для каждого заданного элемента по порядку Инициализатор коллекции вызывает метод Add на целевом объекте с список выражений инициализатора элемента в виде списка аргументов, применяя нормальное разрешение перегрузки для каждого вызова. Таким образом объект коллекции должен содержать применимый метод Add для каждого инициализатор элемента.

Ответ 2

Ваше выражение работает, потому что синтаксис инициализации коллекции использует метод Add() для добавления элементов в коллекцию, а не для установки члена в новый экземпляр коллекции. По сути, ваш код эквивалентен:

var order = new Order();
order.Items.Add(new OrderItem());
order.Items.Add(new OrderItem());

Это прекрасно, потому что вы используете только метод getter.