¿Por qué es necesario llamar a :este() en una estructura para el uso de las propiedades automáticas en c#?

StackOverflow https://stackoverflow.com/questions/272153

Pregunta

Si defino un struct en C# usando las propiedades automáticas como este:

public struct Address
{
    public Address(string line1, string line2, string city, string state, string zip)
    {
        Line1 = line1;
        Line2 = line2;
        City = city;
        State = state;
        Zip = zip;
    }

    public string Line1 { get; protected set; }
    public string Line2 { get; protected set; }
    public string City { get; protected set; }
    public string State { get; protected set; }
    public string Zip { get; protected set; }
}

Cuando intento generar el archivo, me sale un error de compilación diciendo: The 'this' object cannot be used before all of its fields are assigned to.Esto se puede solucionar cambiando el constructor para hacer un encadenado llamada al constructor por defecto como esta:

public Address(string line1, string line2, string city, string state, string zip): this()
{
    Line1 = line1;
    Line2 = line2;
    City = city;
    State = state;
    Zip = zip;
}

Mi pregunta es, ¿por qué este trabajo, y lo que está sucediendo?Tengo una conjetura, y traté de demostrarlo mirando IL, pero yo sólo estoy bromeando yo si creo que puede romper IL.Pero mi conjetura es que, el auto de propiedades de trabajo por tener el compilador de generar campos de sus propiedades detrás de las escenas.Los campos no se puede acceder a través de código, todos los ajustes y conseguir que se debe hacer a través de las propiedades.A la hora de crear una estructura, un constructor por defecto no puede ser definido explícitamente.Así que detrás de las escenas, el compilador debe generar un constructor predeterminado que establece los valores de los campos que el desarrollador no puede ver.

Cualquier y todos los IL asistentes son bienvenidos para probar o refutar mi teoría.

¿Fue útil?

Solución

Nota: a partir de C # 6, esto no es obligatorio, pero de todos modos debería usar propiedades implementadas automáticamente de solo lectura con C # 6 ...

this() se asegura de que los campos estén definitivamente asignados en lo que respecta al compilador; establece todos los campos a sus valores predeterminados. Debe tener una estructura completamente construida antes de poder comenzar a acceder a cualquier propiedades.

Es molesto, pero así son las cosas. ¿Estás seguro de que realmente quieres que esto sea una estructura? ¿Y por qué usar un setter protegido en una estructura (de la que no se puede derivar)?

Otros consejos

Una propiedad no es más que una encapsulación de un Get método y/o un Set método.El CLR tiene metadatos que indica que los métodos en particular debe ser considerada como una de las propiedades, lo que significa compiladores deberían permitir que algunas de las construcciones que no permitiría que con los métodos.Por ejemplo, si X es una propiedad de lectura y escritura de Foo, un compilador puede traducir Foo.X += 5 en Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5) (a pesar de que los métodos se denominan de manera diferente, y generalmente no son accesibles por el nombre).

Aunque un autoproperty implementa un par de métodos get/set, que el acceso a un campo privado de tal manera como se comportan más o menos como un campo, desde el punto de vista de cualquier código fuera de la propiedad, un autoproperty es un par de métodos get/set como cualquier otra propiedad.En consecuencia, una declaración como Foo.X = 5; se traduce como Foo.SET_X_METHOD(5).Ya que el compilador de C# sólo ve que como una llamada de método, y puesto que los métodos no incluyen ningún tipo de metadatos para indicar qué campos se leer ni escribir, el compilador va a prohibir la llamada al método, a menos que se sabe todos los campos de la Foo ha sido escrito.

Personalmente, mi consejo sería evitar el uso de autoproperties con tipos de estructura.Autoproperties sentido con las clases, ya que es posible que las propiedades de la clase para apoyar funciones como notificaciones de actualización.Aunque las primeras versiones de una clase no admiten la actualización de las notificaciones, el hecho de tener esas versiones utilizan un autoproperty en lugar de un campo significa que las futuras versiones puede añadir actualización-funciones de notificación sin necesidad de los consumidores de la clase para ser procesados.Estructuras, sin embargo, no se puede dar un apoyo significativo a la mayoría de los tipos de características que uno podría añadir a campo de propiedades.

Además, las diferencias de rendimiento entre los campos y propiedades es mucho mayor con grandes estructuras de tipos de clase.De hecho, gran parte de la recomendación para evitar los grandes estructuras es una consecuencia de esta diferencia.Las grandes estructuras de la realidad puede ser muy eficiente, si uno evita la copia de ellos innecesariamente.Incluso si uno tenía una enorme estructura HexDecet<HexDecet<HexDecet<Integer>>>, donde HexDecet<T> contenidos expuestos campos F0..F15 de tipo T, una afirmación como Foo = MyThing.F3.F6.F9; simplemente exige la lectura de un número entero de MyThing y guardarlo en Foo, aunque MyThing sería enorme por struct normas (4096 enteros ocupando 16K).Además, uno podría actualización de ese elemento muy fácilmente, por ejemplo MyThing.F3.F6.F9 += 26;.Por el contrario, si F0..F15 se auto-propiedades, la declaración de Foo = MyThing.F3.F6.F9 requeriría la copia de 1K de datos de MyThing.F3 temporal (llamada temp1, luego de 64 bytes de datos de temp1.F6 a temp2) antes de finalmente llegar en torno a la lectura de los 4 bytes de datos de temp2.F9.Ick.Peor, tratando de agregar 26 al valor en MyThing.F3.F6.F9 requeriría algo como var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;.

Muchos de los de larga data de las quejas sobre "mutable tipos de estructura" son en realidad las quejas acerca de los tipos de estructura con propiedades de lectura y escritura.Simplemente reemplace con las propiedades de los campos y los problemas desaparecen.

PS:Hay veces que puede ser útil disponer de una estructura cuyo acceso de las propiedades de un objeto de la clase a la que se contiene una referencia.Por ejemplo, sería bueno tener una versión de un ArraySegment<T> clase que permite una para decir Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;, y la última declaración de añadir nueve a elemento (25+6) de foo.En versiones anteriores de C# se podría hacer eso.Desafortunadamente, el uso frecuente de autoproperties en el Marco donde los campos habría sido más apropiado llevado a una de las quejas sobre el compilador que permite la propiedad incubadoras para ser llamado inútilmente en leer sólo de las estructuras;en consecuencia, llamar a cualquier establecedor de la propiedad de sólo lectura de la estructura de ahora está prohibido, ya sea o no el establecedor de la propiedad en realidad iba a modificar alguno de los campos de la estructura.Si la gente simplemente se abstuvo de hacer estructuras mutable a través de la propiedad incubadoras (hacer que los campos sean directamente accesibles a la hora de mutabilidad era apropiado) compiladores nunca han tenido que aplicar la restricción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top