When you create an auto-property the compiler automatically generates backing fields to support it. In the case of a readonly (get
only) property this is still the case. Being able to assign to a get
-only property in the constructor is simply syntactic sugar supported by the compiler. When you assign to the property, the compiler translates the code so that it assigns to the backing field instead.
For example, assume your constructor:
public MyClass(int myProp)
{
this.MyProp = myProp;
}
This is translated by the compiler to something akin to the following:
public MyClass(int myProp)
{
this._myPropBackingField = myProp;
}
The fact that you have no set
accessor then prevents you from assigning to the property everywhere else.
In reality, the backing field recieves an "unspeakable" name that is illegal c# (but valid IL) thus preventing you from attempting to use the field directly. Your example actually looks like the following after the compiler has done its job:
public class MyClass
{
[CompilerGenerated]
private readonly int <MyProp>k__BackingField;
public int MyProp
{
[CompilerGenerated]
get
{
return this.<MyProp>k__BackingField;
}
}
public MyClass(int myProp)
{
this.<MyProp>k__BackingField = myProp;
}
}
Note that the constructor is actually assigning to the backing field <MyProp>k__BackingField
directly rather than indirectly via the property's set
ter (since after all one does not exist).
See this SharpLab example.