Readonly field in object initializer

Object Initializer internally uses a temporary object and then assign each value to the properties. Having a readonly field would break that.

Following

TestStruct ts = new TestStruct 
{
     TestField = "something";
};

Would translate into

TestStruct ts;
var tmp = new TestStruct();
tmp.TestField = "something"; //this is not possible
ts = tmp;

(Here is the answer from Jon Skeet explaining the usage of temporary object with object initalizer but with a different scenario)


C# 9 Init-Only Properties, despite the name, will allow the initializer syntax to be able to set readonly fields as well.

Here are the relevant parts copied from the links.

Init-only properties

Here's a simple example of object initializer.

new Person
{
    FirstName = "Scott",
    LastName = "Hunter"
}

The one big limitation today is that the properties have to be mutable for object initializers to work: They function by first calling the object’s constructor (the default, parameterless one in this case) and then assigning to the property setters.

Init-only properties fix that! They introduce an init accessor that is a variant of the set accessor which can only be called during object initialization:

public class Person
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

With this declaration, the client code above is still legal, but any subsequent assignment to the FirstName and LastName properties is an error.

Init accessors and readonly fields

Because init accessors can only be called during initialization, they are allowed to mutate readonly fields of the enclosing class, just like you can in a constructor.

public class Person
{
    private readonly string firstName;
    private readonly string lastName;
    
    public string FirstName 
    { 
        get => firstName; 
        init => firstName = (value ?? throw new ArgumentNullException(nameof(FirstName)));
    }
    public string LastName 
    { 
        get => lastName; 
        init => lastName = (value ?? throw new ArgumentNullException(nameof(LastName)));
    }
}

This is not possible. since readonly fields cannot be assigned from other than Constructor or Field Initializer.

What you show is actually object initializer. It is just a syntatic sugar, gets comiled into something like this

TestStruct ts;
TestStruct ts1 = new TestStruct();
ts1.TestField = value;
ts = ts1;

Is that clear why it doesn't compile?


readonly means that the field can only be set in the constructor (or in a field initializer). Properties specified in the object initializer are set after the constructor has returned. That is,

TestStruct ts = new TestStruct {
    TestField = "something"
};

is basically equivalent to

TestStruct ts = new TestStruct();
ts.TestField = "something";

(In a Debug build, the compiler may use a temporary variable, but you get the idea.)

Tags:

C#

Readonly