18

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;
    }
}
thisextendsthat
  • 1,266
  • 1
  • 9
  • 26
  • Non-abstract auto-properties always use a backing field. Setting the property inside the class is translated to setting the backing field. Event work in a similar fashion. – IS4 Sep 24 '17 at 14:58

3 Answers3

40

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    Not just a thorough answer but from Jon Skeet himself! Amazing, thank you :) – thisextendsthat Sep 23 '17 at 16:05
  • Funny that in `vb.net` you can access that "generated" field by adding underscore to the property name `_Thing` and even change value :). – Fabio Sep 23 '17 at 16:10
  • 2
    @Fabio: Yikes. Fortunately in C# it's given a name like `k__BackingField`, and the `<>` make it invalid as an identifier. – Jon Skeet Sep 23 '17 at 16:11
4

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

Michal Ciechan
  • 13,492
  • 11
  • 76
  • 118
0

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.

Arthur Attout
  • 2,701
  • 2
  • 26
  • 49
  • My question is _how_ does that happen, in IL if the setter method doesn't exist? How does the constructor set call to the property actually work, under the covers. – thisextendsthat Sep 23 '17 at 16:00