2011-04-06 16 views
6

Hace poco estuve investigando los internos de la estructura CancellationToken y descubrí un poco de construcción extraña (para ser más precisos, asignación de valor a la palabra clave this).Asignación de un valor de estructura a esta palabra clave

Código de uno de sus constructores es como sigue:

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

¿Cuál es el significado de la línea en la que se realice la cesión a this palabra clave?

Tenga en cuenta que la asignación a la palabra clave this no es posible para las clases - se produce el error Cannot assign to '<this>' because it is read-only.

Respuesta

6

Esta es una característica muy poco conocida de C# - esto permite que una estructura sobrescriba sus propios datos. No estoy seguro de si esto solo está disponible para tipos de valores blittables o no (supongo que no).

En cuanto a la aplicación práctica va, no vas a encontrar muchos usos para este ..

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 en ello más, hay una diferencia fundamental en lo que "este" se refiere a cuando estás tratar con tipos de valores vs tipos de referencia.

Cuando llamas "this" en un tipo de referencia, lo que obtienes es un puntero que vive en la pila, en realidad no obtienes el objeto en sí. El puntero se desreferencia implícitamente de nuevo al objeto en el montón, que abstrae la indirección. Ahora bien, si usted ha dicho algo así como esta nueva MyReferenceType =(), que ha cambiado el puntero para apuntar a un objeto diferente en el montón el ámbito actual - usted tiene no cambió el propio objeto original en el montón, ni ¿Alguna otra referencia/puntero ahora se refiere al nuevo objeto Heap? Es muy probable que tan pronto como su puntero mutado quede fuera de alcance, el nuevo objeto de montón que haya creado estará sujeto a la recolección de basura.

Cuando llama a "this" en un tipo de valor, obtiene el objeto real, no una referencia o un puntero. No hay direccionamiento indirecto, por lo que puede sobrescribir los bits sin formato en esta ubicación de memoria (que es exactamente lo que hace el constructor predeterminado).

1

Sólo una conjetura:

Cada clase es un tipo de referencia sentido de que la memoria se asigna en el montón y la persona que llama tiene acceso a los datos reales a través del puntero. Por ejemplo:

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 estructura es un tipo de valor significado que la memoria se asigna en la pila y la persona que llama se ocupa de la instancia real en lugar de con la referencia a esa instancia.Por ejemplo:

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

Teniendo en cuenta el ejemplo:

this = new Customer(); 

Realización de la siguiente operación en una estructura simplemente inicializa con valores cero:

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 

No sé por qué no es Es posible con los tipos de referencia, pero mi suposición es que habrá que atravesar todo el gráfico del objeto para "restablecerlo" por completo (lo que podría no ser una tarea fácil). Supongo que esto valdrá la pena en caso de referencias circulares.

Una vez más, esto es sólo mi pensamiento y me gustaría que alguien pruebe o descarte (con una explicación, por supuesto) de ellos.

Cuestiones relacionadas