Framework Tips XI: What is this?

Lately while going through the code of latest MEF release, I stumbled upon a piece of code that used a very little known feature of .NET

Just take a look:

public struct Tuple<TFirst, TSecond>
    public Tuple(TFirst first, TSecond second)
        this = new Tuple<TFirst, TSecond>();//looks strange?
        this.First = first;
        this.Second = second;

I myself was shocked at first. “Hey! You can’t assign to this! It’s against the nature and common sense.” Then I went to C# language specification to look for explanation and indeed I’ve found it.

The key here is the fact that Tuple is a struct, not a class. As it turns out, the meaning of this differs between those two.

The explanation comes from chapter 11.3.6 – Meaning of this

Within an instance constructor or instance function member of a class, this is classified as a value. Thus, while this can be used to refer to the instance for which the function member was invoked, it is not possible to assign to this in a function member of a class.

Within an instance constructor of a struct, this corresponds to an out parameter of the struct type, and within an instance function member of a struct, this corresponds to a ref parameter of the struct type. In both cases, this is classified as a variable, and it is possible to modify the entire struct for which the function member was invoked by assigning to this or by passing this as a ref or out parameter.

It makes total sense when you think about it, still – I think many experienced people can be surprised by that.

Technorati Tags:


Sidar Ok says:

this is indeed an interesting find !

Hmmmm, so why would you want to do this? What purpose does it serve in the code snippet you provided?

Is it not implicit that the struct has already been initialised with a default-constructed instance before entry into that constructor?

Well, here’s the catch – remove the first line, and then try to compile.
Oh, and First, and Second are properties, not fields.

Bevan Arps says:

Interesting way to work around a bug – but wouldn’t it be simpler to just chain the constructors as you should …

public Tuple(TFirst first, TSecond second) : this() { … }

Then everything works the way it should without needing any kung fu!