Search code examples
c#object-initializers

C# nested object initializer


C# 5.0 Language Specification 7.6.10.2 Object initializers states that

A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

While I understand read-only fields cannot be modified by the initializers after the constructor is run, I do not have a clue about the restriction on properties.

The following is a code sample I used to test this restriction on properties:

using System;

namespace ObjectCollectionInitializerExample
{
    struct MemberStruct
    {
        public int field1;
        public double field2;
    }
    class ContainingClass
    {
        int field;
        MemberStruct ms;
        public int Field
        {
            get { return field; }
            set { field = value; }
        }
        public MemberStruct MS
        {
            get { return ms; }
            set { ms = value; }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            // Nested object initializer applied to a property of value type compiles!
            ContainingClass cc = new ContainingClass { Field = 1, MS = new MemberStruct { field1 = 1, field2 = 1.2} };
            Console.ReadKey();
        }
    }
}

I commented on the code where it was supposed to generate a compiler error based on the specification. But it compiles successfully. What am I missing here?

Thanks


Solution

  • What you have is not a nested object initializer because you explicitly create a new instance of MemberStruct. The inner object initializer doesn't directly follow the equals sign, but is an object initializer on its own associated with the call to the MemberStruct constructor.

    This is how using a nested object initializer would look like:

    ContainingClass cc = new ContainingClass { Field = 1, MS = { field1 = 1, field2 = 1.2} };
    

    This will not compile when MS is a value type (struct), but it will compile when MS is a reference type (object).