Atribuição de um valor de estrutura a esta palavra-chave

Eu estava recentemente analisando internamente a estrutura do CancellationToken e descobri um pouco de construção estranha (para ser mais preciso, atribuição de valor a this palavra this chave).

O código de um de seus construtores é o seguinte:

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

Qual é o significado da linha na qual a designação para this palavra this chave ocorre?

Por favor, note que a atribuição a this palavra-chave não é possível para as classs – erro Cannot assign to '' because it is read-only ocorre.

Esse é um recurso muito pouco conhecido do C # – isso permite que uma estrutura sobrescreva seus próprios dados. Eu não tenho certeza se isso está disponível apenas para tipos de valor blittable ou não (eu estou adivinhando não).

No que diz respeito à aplicação prática, você não encontrará muitos usos para isso.

 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... } 

Pensando mais nisso, há uma diferença fundamental no que “isso” significa quando você está lidando com tipos de valor versus tipos de referência.

Quando você chama “this” em um tipo de referência – o que você obtém é um ponteiro que mora na pilha, na verdade você não obtém o próprio object. O ponteiro implicitamente desreferencia de volta para o object na pilha, que abstrai a indireção. Agora, se você disse algo como isto = new MyReferenceType () , você alterou o ponteiro para apontar para um object de heap diferente no escopo atual – você não alterou o próprio object original no heap, nem quaisquer outras referências / pointers Agora, consulte o novo object heap. É muito provável que, assim que seu ponteiro com mutação sair do escopo, o novo object de heap criado por você esteja sujeito à garbage collection.

Quando você chama “this” em um tipo de valor – você está obtendo o object real, não uma referência ou ponteiro. Não há nenhuma indicação indireta, então você está livre para sobrescrever os bits brutos neste local de memory (que é exatamente o que o construtor padrão faz).

Apenas um palpite:

Cada class é um tipo de referência, o que significa que a memory é alocada no heap e o chamador obtém access aos dados reais através do ponteiro. Por exemplo:

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

Cada struct é um tipo de valor, o que significa que a memory é alocada na pilha e o chamador lida com a instância real em vez de com a referência a essa instância. Por exemplo:

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

Considerando o seu exemplo:

 this = new Customer(); 

Executar a seguinte operação em uma estrutura simplesmente inicializa com valores zero:

 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 

Eu não sei porque não é possível com os tipos de referência, mas o meu palpite é que isso exigirá que o gráfico do object inteiro seja completamente “redefinido” (o que pode não ser uma tarefa fácil). Presumo que isso valha a pena no caso de referências circulares.

Mais uma vez, este é apenas o meu pensamento e eu gostaria muito que alguém provasse ou descartasse (com uma explicação, é claro) eles.