Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assignment of a struct value to this keyword

I was recently looking into internals of CancellationToken structure and discovered a bit of weird construct (to be more precise, assignment of value to this keyword).

Code of one of its constructors is as following:

public CancellationToken( bool canceled )
{
    this = new CancellationToken();
    if ( canceled )
    {
        this.m_source = CancellationTokenSource.InternalGetStaticSource( canceled );
    }
}

What is the meaning of line on which the assignment to this keyword occurs?

Please note that assignment to this keyword is not possible for classes - error Cannot assign to '<this>' because it is read-only occurs.

like image 297
Rest Wing Avatar asked Apr 06 '11 07:04

Rest Wing


2 Answers

This is a very little known feature of C# - this allows a struct to overwrite its own data.

As far as practical application goes, you're not going to find many uses for this..

struct MyStruct
{
    int a = 1;
    int b = 2;
    int c = 3;

    public void Mutate()
    {
        a = 10;
        b = 20;
        c = 30;
    }

    public void Reset()
    {
        a = 1;
        b = 2;
        c = 3;
    }

    public void Reset2()
    {
        this = new MyStruct();
    }

    // The two Reset methods are equivilent...
}

Thinking about it more, there's a fundamental difference in what "this" means when you're dealing with value types vs reference types.

When you call "this" on a reference type - what you get is a pointer that lives on the stack, you don't actually get the object itself. The pointer implicitly dereferences back to the object on the heap, which abstracts the indirection. Now if assigning to this in classes were possible, and you'd have said something like this = new MyReferenceType(), you'd have changed the pointer to point to a different heap object in the current scope - you wouldn't have changed the original object itself in the heap, nor would it have caused any other references/pointers to refer the new heap object. Its very likely that as soon as your mutated pointer would have gone out of scope - the new heap object you'd have created would have been subject to garbage collection.

When you call "this" on a value type - you are getting the actual object, not a reference or pointer. There is no indirection so you are free to overwrite the raw bits at this memory location (which is exactly what the default constructor does).

like image 109
MattDavey Avatar answered Oct 02 '22 03:10

MattDavey


Just a guess:

Every class is a reference type meaning that the memory is allocated in the heap and the caller gets access to the actual data through the pointer. For example:

Customer c1 = new Customer('CUSTID');   // "Customer" is a reference type 
Customer c2 = c1;   // "c1" and "c2" points to the same memory within the heap

Every struct is a value type meaning that the memory is allocated in the stack and the caller deals with the actual instance rather than with the reference to that instance. For example:

Customer c1 = new Customer('CUSTID');    // "Customer" is a value type 
Customer c2 = c1;   // New memory gets allocated for "c2" within the stack

Considering your example:

this = new Customer();

Performing the following operation on a struct simply initializes it with zero values:

mov eax,dword ptr [ebp-3Ch] ; Save pointer to "ebp-3Ch" in EAX register
xor edx,edx                 ; Clear EDX register
mov dword ptr [eax],edx     ; Write "zero" by address containing in EAX

I don't know why it's not possible with reference types but my guess is that in will require traversing of the entire object graph to "reset" it completely (which might be not an easy task). I assume that this will become worth in case of circular references.

Again, this is just my thoughts and I'd very much like someone to either prove or discard (with an explanation, of course) them.

like image 21
volpav Avatar answered Oct 02 '22 05:10

volpav