I've been using C# for a while, but recently noticed that the behaviour of one of my unit tests changed depending on which variation of collection initialiser expression I used:
var object = new Class { SomeCollection = new List<int> { 1, 2, 3 } };
var object = new Class { SomeCollection = { 1, 2, 3 } };
Up until this point I assumed that the second form was just syntactic sugar and was semantically equivalent to the first form. However, switching between these two forms resulted in my failing unit test passing.
The example code below demonstrates this:
void Main()
{
var foo1 = new Foo { Items = new List<int> { 1, 2, 3} };
var foo2 = new Foo { Items = { 1, 2, 3 } };
foo1.Dump();
foo2.Dump();
}
class Foo
{
public List<int> Items { get; set; }
}
When I run this, the first assignment works fine but the second results in a NullReferenceException
.
My gut feeling is that behind the scenes the compiler is treating these two expressions as this:
var foo1 = new Foo();
foo1.Items = new List<int> { 1, 2, 3 };
var foo2 = new Foo();
foo2.Items.Add(1);
foo2.Items.Add(2);
foo2.Items.Add(3);
Is that assumption accurate?
Yes, your assumption is accurate. If an object initializer just has:
{
Property = { ... }
}
rather than
{
Property = expression
}
then the setter for the property isn't used - the getter is used, and then either the Add
method is called, or properties are set within the returned value. So:
var foo = new Foo
{
Collection = { 1 }
Property =
{
Value = 1
}
};
is equivalent to:
// Only the *getters* for Collection and Property are called
var foo = new Foo();
foo.Collection.Add(1);
foo.Property.Value = 1;
Compare that with:
var foo = new Foo
{
Collection = new List<int> { 1 },
Property = new Bar { Value = 1 }
};
which is equivalent to:
// The setters for Collection and Property are called
var foo = new Foo();
foo.Collection = new List<int> { 1 };
foo.Property = new Bar { Value = 1 };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With