1

Given the following 2 classes (VS 2015 + .Net 4.5) with fully mutable properties:

class Wrapped
{
    public int A {get; set;}
    public int B {get; set;}
}

class Wrapper
{
    public int X {get; set;}
    public Wrapped Y  {get; set;}
    public Wrapper()
    {
       Y = new Wrapped  { A = 5, B = 10 };
    }
}

I was intrigued to discover that Resharper 8.x recommended the usage of the Object Initializer Syntax (UseObjectOrCollectionInitializer) in the following nested initialization scenario, where I intended only a partial assignment of the wrapped entity - I wanted that the remainder of the Wrapped instance properties should retain any default values issued by the Wrapper class constructor:

// My Original code
var demo1 = new Wrapper
{
    X = 5
};
demo1.Y.B = 23;

// Resharper's refactoring suggestion
var demo2 = new Wrapper
{
    X = 5,
    Y = { B = 23 }
};

Initially, I assumed that the refactoring might be syntactic sugar for:

    new Wrapper
    {
        X = 5,
        Y = new Wrapped { B = 23 }
    };

Which is obviously not the same as my code, as it will wastefully construct and assign property Y twice (Once in Wrapper's default constructor and once in the assignment of Y, and worse, the setter it will lose any other property values assigned by Wrapper's constructor as it will assume any values assigned by Wrapped's constructor.

However, upon IL disassembly with LinqPad I was amazed that Resharper was correct, viz that the initializer syntax:

Y = { B = 23 }

is equivalent to an explicit

demo1.Y.B = 23;

So my question is : Is there a formal reference for this "partial" (i.e. non-reconstructed) assignment syntax within the object intitialization syntax. I couldn't easily find one on MSDN, e.g. Object and Collection Initializers, so I can weigh up the relative benefits and dangers of this syntax?

Edit

Also, noted that, just like the explicit syntax, that

Y = { B = 23 }

Will throw a NullReferenceException unless B is constructed inside of Y's constructor.

IL Disassembly:

i.e. both demo1 and demo2 result in this IL:

Wrapper..ctor
Wrapper.set_X
Wrapper.get_Y
Wrapped.set_B

Whereas demo3 results in the incorrect

Wrapper..ctor
Wrapper.set_X
Wrapped..ctor
Wrapped.set_B
Wrapper.set_Y

I've put a small sample showing the differences between 1&2, and 3 on IdeOne here

StuartLC
  • 104,537
  • 17
  • 209
  • 285

0 Answers0