2012-03-10 14 views
30

acabo de estar navegando en un archivo reflector y visto esto en un constructor estructura:C# "Las estructuras de este = ...."

this = new Binder.SyntaxNodeOrToken(); 

no he visto que la terminología antes. ¿Puede alguien explicar qué significa esta tarea en C#. Es difícil para Google.

+1

A menos que esté loco, eso es un error. – ChaosPandion

+0

@ ChaosPandion: O los dos estamos locos o estoy de acuerdo. Tal vez reflector idiota? –

+1

@ ChaosPandion esto es completamente legal para 'struct' en C# – JaredPar

Respuesta

53

Reemplaza el valor, básicamente. Efectivamente copia todos los campos desde el lado derecho hacia el izquierdo ... excepto que funciona incluso si los campos son de solo lectura. Y sí, es se ve muy raro, y es un poco aterrador.

Ejemplo:

using System; 

class Test 
{ 
    static void Main() 
    { 
     Point point = new Point(10, 20); 
     point.ReplaceWith(new Point(2, 3)); 
     Console.WriteLine(point); // (2, 3) 
    } 
} 

struct Point 
{ 
    private readonly int x; 
    private readonly int y; 

    public Point(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public void ReplaceWith(Point other) 
    { 
     this = other; 
    } 

    public override string ToString() 
    { 
     return string.Format("({0}, {1})", x, y); 
    } 
} 

Para obtener más información, lea la sección 7.6.7 de la especificación C# 4, que incluye:

  • [texto acerca de su uso en un constructor struct]

  • Cuando this se utiliza en una expresión primaria dentro de un método de instancia o acceso de instancia de una estructura, se clasifica como una variable. El tipo de la variable es el tipo de instancia de la estructura dentro de la cual ocurre el uso.

    • Si el método o de acceso no es un iterador, la variable this representa la estructura para que se invocó el método o de acceso, y se comporta exactamente de la misma como un parámetro ref del tipo struct.

    • [texto sobre iteradores]

+0

Esto es tan raro ... C# está abrumando mi concepto de programación (tal vez muchos otros también) – ziq

+3

@ziq: No olvide que 'this' es" todo el valor "en un tipo de valor, no una referencia. Creo que esa es la parte crítica. –

+0

¿Cómo se puede realizar? Reemplazar a uno mismo mientras se ejecuta una función miembro (en este ejemplo Reemplazar con – ziq

5

Si s1 y s2 son estructuras de tipo Foo, con campos f1, f2 y f3, de tipos t1, t2 y t3, la La declaración s1 = s2 es semánticamente equivalente a

 
    s1.f1 = s2.f1; 
    s1.f2 = s2.f2; 
    s1.f3 = s2.f3; 

salvo que uno no debe asumir el orden de las operaciones de asignación (o incluso el orden relativo de lecturas y escrituras; el código generado podría, por ejemplo, leer los tres campos en registros, y luego escribir los tres campos). Todos los campos se copiarán, independientemente de si son públicos o privados, mutables o los llamados inmutables. No se llamará a los getters o setters de propiedades; ni la estructura de origen ni la de destino recibirán ninguna notificación de que los campos de las estructuras se están duplicando o sobrescribiendo.

Una declaración this = new Foo(whatever); es en C# (*) equivalente a

 
    Foo temp; 
    call Foo's constructor (out temp, whatever); 
    this.f1 = temp.f1; 
    this.f2 = temp.f2; 
    this.f3 = temp.f3; 

(*) semántica Struct constructor en VB.net son diferentes

Como se indicó anteriormente, las asignaciones de campo se realizan independientemente de si los campos son públicos o privados, y sin importar si son supuestamente inmutables.

Una de las razones creo (en contra de la opinión de otras personas) que estructuras a menudo se debe exponer a campos variables es que sintaxis como:

 
    // Assume myKVP is a field of type KeyValuePair<Wizzle, int> 
    rr = new KeyValuePair<myKVP.Key, myKVP.Value+1>; 

hace que parezca como si myKVP se referirá a una instancia diferente después la asignación de lo que tenía antes, cuando lo que está sucediendo realmente es:

 
// Assumes backing fields are named _Key and _Value 
// Note that C# won't allow one to write private fields directly, but the 
// act of copying one struct instance to another copies all the fields, 
// public and private, from the source instance to the destination. 
    KeyValuePair<Wizzle, int> temp; 
    temp._Key = myKVP.Key; // Constructor has access to backing fields 
    temp._Value = myKVP.Value+1; 
    myKVP._Key = temp._Key; // Struct assignment copies all fields, public and private 
    myKVP.Value = temp.Value; 

En otras palabras, la declaración no hace myKVP informe a una instancia diferente; en su lugar, crea una nueva instancia, muta la instancia anterior al sobrescribir sus campos con los de la instancia nueva y luego descarta la nueva instancia. Si algún código estaba evaluando myKVP.ToString() mientras se llevaba a cabo la asignación anterior, la mutación afectaría a la instancia de myMVP que se estaba imprimiendo.

Las estructuras pueden tener una semántica útil, pero las llamadas estructuras "inmutables" no lo son. Las estructuras no triviales (aquellas para las que es posible crear un valor diferente del predeterminado) son mutables si y solo si se mantienen en las ubicaciones de almacenamiento mutable , independientemente de cualquier semántica impuesta por el tipo. Estructuras mutantes, es decir, estructuras que modifican this en cualquier método, excepto en constructores y establecedores de propiedades, pueden tener algunos comportamientos inesperados porque los compiladores no pueden prohibir la invocación de otros métodos que mutarán this en las instancias de estructura inmutables. La exposición pública de los campos estructurales, sin embargo, no representa ningún peligro. Dado que todos los campos de una instancia mutable de una estructura no trivial son inherentemente modificables, independientemente de los intentos que la estructura pueda hacer para permitir la mutación, y todos los campos de una instancia inmutable de una estructura son inmutables incluso si están expuestos, una estructura que se esfuerza por hacer que sus campos sean "inmutables" realmente está mintiendo. Una mentira que a veces puede ser útil (por ejemplo, si se supone que los contenidos del campo obedecen a ciertas invariantes) pero que no se debe contar sin una causa real.

+0

No sigo tu argumento. Su ejemplo de sintaxis 'myKVP' es confuso y no parece seguir la gramática C#. Si una estructura está destinada a ser inmutable, ¿por qué debería contener "otros métodos que mutarán' this' "? Y parece haber cierta confusión en su último párrafo sobre la diferencia entre un * tipo de valor * y las * instancias * de ese tipo. ¿Podría editar su respuesta para explicar mejor lo que está tratando de decir? –

+0

@DanielPryden: Acabo de agregar un par de comentarios más e intenté aclarar el último párrafo. La pregunta original era por qué uno puede reemplazar 'this' con otra estructura. La razón por la que uno puede hacer eso es porque uno realmente no está reemplazando a 'esto'; uno simplemente está reemplazando los contenidos de todos sus campos con los de la otra estructura. Quería decir que el hecho de que uno puede mutar "esto", ya sea sobrescribiendo todo o alterando sus campos, no significa que uno deba hacerlo. – supercat

Cuestiones relacionadas