A 2 post collection

Getter-only autoproperties?

 •  Filed under C#, Programming, Roslyn

Sparked by a recent question on Stack Overflow, I thought I’d write up a post about this topic, both for my own reminder later and also to ensure I understand the concepts myself.

In this article I’ll dissect autoproperties in C# with only a getter, and how/why they can be written to in a constructor.

The topic of this question is code like this:

public class Foo
    public int Bar { get; }
    public Foo()
        Bar = 5;

Here’s some typical questions:

  • If the property doesn’t have a setter, how was I able to set it in the constructor?
  • Did the compiler add a private setter for me?
  • Is this really immutable?

The answer lies in how the C# compiler automagically rewrote the above code.

You can see the above code in its real form by using SharpLab, try it now.

The code that the compiler generates looks like this:

public class Foo
    private readonly int <Bar>k__BackingField;
    public int Bar
            return this.<Bar>k__BackingField;
    public Foo()
        this.<Bar>k__BackingField = 5;

Here are the important bits:

  • The compiler silently added a backing field. It gave it a name that syntactically isn’t legal C#, to avoid a collision with any backing fields provided by the programmer.
  • This backing field is declared as readonly, making the class immutable.
  • The getter is rewritten to return the value of this backing field.
  • The constructor is also rewritten to write to the backing field instead of the property. * This “circumvents” the issue of not having a setter for the property, you’re not really setting the property directly, but setting the backing field.

So there you have it. There’s a bit of magic going on, but being able to not have to declare and deal with the backing field makes writing immutable classes much easier.

Tuples with named members in C# 7 – Smoke and mirrors I tell ya’

 •  Filed under C#, Programming, Roslyn, Tuples

So I’ve been looking at the new syntax that is introduced with C# 7 and tuples with named members caught my eye, specifically I wonder how they had solved it without introducing type explosion.

Consider the following code that doesn’t use named members:

public (string, int) GetMyIdentity() => ("Lasse", 45);

When using the resulting tuple in code, you have access to two fields, Item1 and Item2, like this:

var tuple = GetMyIdentity();
Console.WriteLine($"Name={tuple.Item1}, Age={tuple.Item2}");

However, you can also name the members, like this:

public (string name, int age) GetMyIdentity() => ("Lasse", 45);

And now both Item1/Item2 and name/age are legal members, the following code will compile and run just fine:

var tuple = GetMyIdentity();
Console.WriteLine($"Name={tuple.<strong>Item1</strong>}, Age={tuple.Item2}");
Console.WriteLine($"Name={tuple.<strong>name</strong>}, Age={tuple.age}");

So how did they solve this? Did they create extra properties that simply redirect to Item1/Item2?

No, this is entirely smoke and mirrors. It is a compiler trick.

Let’s take a look at the declaration again and show a hidden attribute:

[TupleElementNames(new[] { "name", "age" })]
public (string, int) GetMyIdentity() => ("Lasse", 45);

The names are injected by an attribute and then the compiler fakes the entire thing at the call site. Basically, every access to the named members name and age are substituted with access to Item1 and Item2 respectively.

We can use LINQPad to compile a very simple program and look at its IL:


This is the resulting IL:

IL_0000: ldarg.0 
IL_0001: call UserQuery.GetMyIdentity
IL_0006: ldfld System.ValueTuple<System.String,System.Int32>.Item1
IL_000B: call System.Console.WriteLine
IL_0010: ret

Notice there is no trace of the name member in the compiled code.

The attribute is used in conjunction with these types of declarations:

  • Method return types
  • Properties
  • Fields
  • Method parameters

The attribute is not, however, used for local variables because they’re not needed. The compiler is holding the method in memory while compiling it so it knows exactly what those members should be named, let’s fire up LINQPad again:

var tuple = (name: "Lasse", age: 45);

Is compiled into this:

IL_0000: ldstr "Lasse"
IL_0005: ldc.i4.s 2D 
IL_0007: newobj System.ValueTuple<System.String,System.Int32>..ctor
IL_000C: ldfld System.ValueTuple<System.String,System.Int32>.Item1
IL_0011: call System.Console.WriteLine
IL_0016: ret</pre>

Notice that there is no trace of the name member.