C# Property with no setter - how can it get set from constructor?

Viewed 9401

How come you can set a get-only auto-property from a constructor? The code below shows how you can set the property from the constructor but using reflection shows that there really isn't a setter behind the scenes. How does it get set from the constructor call if the setter method doesn't even exist in the IL?

void Main()
{
    var obj = new GetOnlyProperty("original value");
    Console.WriteLine(obj.Thing); //works, property gets set from ctor

    //get the set method with reflection, is it just hidden..?
    //nope, null reference exception
    typeof(GetOnlyProperty)
        .GetProperty("Thing", BindingFlags.Instance | BindingFlags.Public)
        .GetSetMethod()
        .Invoke(obj, new object[]{"can't set me to this, setter doen't exist!"});
}

public class GetOnlyProperty
{
    public string Thing { get; }

    public GetOnlyProperty(string thing)
    {
        Thing = thing;
    }
}
3 Answers

A read-only automatically-implemented property is converted by the compiler into a read-only field and a read-only property. Assignments to the property in the constructor are compiled as assignments to the underlying field.

So your code here:

public class GetOnlyProperty
{
    public string Thing { get; }

    public GetOnlyProperty(string thing)
    {
        Thing = thing;
    }
}

is compiled into IL as if you'd written:

public class GetOnlyProperty
{
    private readonly string _thing;
    public string Thing => _thing;

    public GetOnlyProperty(string thing)
    {
        _thing = thing;
    }
}

... except that _thing is really given an "unspeakable name" that wouldn't be a valid C# identifier.

A read-only property (get only) has a backing readonly field, which as you probably know, can only be set in the constructor.

hence when you have object Property { get; }

this translates to

private readonly object _property;
public object get_Property(){return _property;}

and the compiler knows that if you set the property in the constructor to set the field directly

Because a read-only property should be assigned at a time or another, otherwise its value would always be the default value of the type, and it would be completely useless.

This is what constructors are for (beside other obvious reasons), to assign values to read-only fields.

Related