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.)