Why can I use a collection initializer with private set access from another class?
Consider the following code:
public sealed class Order
{
public Order()
{
Items = new List<OrderItem>();
}
public List<OrderItem> Items { get; private set; }
}
public sealed class OrderItem
{
}
and here's Order
initialization in another class.
var order = new Order
{
Items =
{
new OrderItem(),
new OrderItem()
}
};
Could you explain why it works? As you see the Order
has private set
property, so I thought it would be impossible to set its value.
Your statement works because the collection initialization syntax uses the Add()
method to add the items to the collection rather than setting the member to a new instance of a collection. Essentially, your code is the equivalent of:
var order = new Order();
order.Items.Add(new OrderItem());
order.Items.Add(new OrderItem());
Which is fine since you only ever use the getter method.
Short answer:
It works thru collection initializer which calls Add
to add items
Long answer:
Accodingly C# 3.0 cpesification, object which implement IEnumerable
and has appropiate Add
method can be initialised thru the Add
method.
Items
has public get
accessor and Items
it's a List<T>
which implements IEnumerable
and has Add
. Here's how the compiler sees your code
var order = new Order();
order.Items.Add(new OrderItem());
order.Items.Add(new OrderItem());
Please note, the compiler doesn't use info that the List
implements IEnumerable
, here's the proof, no exception will be thrown
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();
}
}
from C# Language Specification
The collection object to which a collection initializer is applied must be of a type that implements
System.Collections.IEnumerable
or a compile-time error occurs. For each specified element in order, the collection initializer invokes an Add method on the target object with the expression list of the element initializer as argument list, applying normal overload resolution for each invocation. Thus, the collection object must contain an applicableAdd
method for each element initializer.