Search code examples
c#roslync#-6.0object-initialization

Property assignments in object initializers not considered on the same level as auto-properties in C# 6


C#6 introduced the ability to initialize properties without a setter, so that one can now use this kind of syntax

public class MyClass
{
    public int Answer { get; } = 42;
}

or even this

public class MyClass
{
    public int Answer { get; }
    public MyClass() 
    {
        Answer = 42;
    }
}

I know (or rather, strongly assume) that this will be be translated into a generated readonly field with an accessor method in CIL, so I understand how this

public class MyClass
{
    public int Answer { get; }
    public MyClass CreateMyClassInstance()
    {
        return new MyClass()
        {
            Answer = 42
        };
    }
}

does not compile (since the assignment technically occurs outside of a constructor, which conflicts with the restrictions imposed by the backing readonly field).

My question is why is such a behavior prohibited in the first place ? Why, from a syntactic and/or compilation point of view, are the property assignments that are part of an object initializer not just considered as extra inline logic to execute after, but still within the object's constructor ? Is it by design, the result of technical limitations or backwards-compatibility, or maybe just a change that's not important enough to be considered ?


Solution

  • Why is such a behavior prohibited in the first place?

    Allowing a read-only property to be assigned from an object initializer breaks encapsulation. Any initialization done in constructor could be later overriden by client code in object initializer. It would be impossible for classes to hold their invariants.

    Such a feature is not only unnecessary, it's dangerous.

    Why, from a syntactic and/or compilation point of view, are the property assignments that are part of an object initializer not just considered as extra inline logic to execute after, but still within the object's constructor?

    It would mean that for each and every object initializer, the compiler would have to generate a new constructor. Possibly modifying and breaking a type from another assembly.

    Or, the newobj CIL instruction would have to modified to allow execution of some arbitrary code after the constructor.