I have a class with that has a collection-property:
class MyClass
{
public MyCollection Coll { get; private set; }
public MyClass() { this.Coll = new MyCollection(); }
}
class MyCollection : IList { ... }
Now I´m creating two different instances of my class:
var o1 = new MyClass() { Coll = {"1", "2"}};
var o2 = new MyClass() { Coll = new MyCollection() {"1", "2"} };
I understand that compiler complains about the latter as the setter for the property doesn´t exist (or in this case isn´t publicly accessable). The first however is an assignement as well - albeit a collection initializer.
I assume that collection-initializers are allowed for get-only properties as they´re just calling Add
on IList
and do not actually call the getter of the property. Is this right?
From your question:
I assume that collection initializers are [...] just calling
Add
onIList
[...].
This assumption is correct. Collection initializers are syntactic sugar that the C# compiler translates into something more explicit during compilation. For instance, the following line:
var l = new List<int>() { 1, 2 };
Is actually translated to:
var l = new List<int>();
l.Add(1);
l.Add(2);
You can verify this be looking at the generated MSIL (slightly simplified):
newobj List<System.Int32>..ctor // Create list object.
stloc.0 // Store list object as local variable "0".
ldloc.0 // Push local variable "0" onto the stack.
ldc.i4.1 // Push 4-byte integer constant "1" onto the stack.
callvirt List<System.Int32>.Add // Call "Add" (uses and pops the last two values from
// the stack).
ldloc.0 // Push list onto stack again.
ldc.i4.2 // Push constant "2" onto stack.
callvirt List<System.Int32>.Add // Call "Add" again.
This means that your code var o1 = new MyClass() { Coll = {"1", "2"}};
never accesses the private setter. It simply gets Coll
and calls Add
on it like so:
var o1 = new MyClass();
o1.Coll.Add("1");
o1.Coll.Add("2");
Again we can check the MSIL to verify this:
newobj MyClass..ctor
stloc.1 // Store MyClass instance at local variable "1".
ldloc.1 // Load MyClass instance onto stack.
callvirt MyClass.get_Coll // Call getter of "Coll" and push the MyCollection
// instance onto the stack.
ldstr "1" // Push the string "1" onto the stack...
callvirt MyCollection.Add // ...and call "Add".
pop // Discard the return value of "Add".
ldloc.1
callvirt MyClass.get_Coll
ldstr "2"
callvirt MyCollection.Add
pop