Pregunta

Comentando algunas estructuras pequeñas mientras respondía esta publicación , encontré lo siguiente inesperadamente:

La siguiente estructura, utilizando un campo int es perfectamente legal:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Legal assignment.
    } 

    public int Size; 
}

Sin embargo, la siguiente estructura, que utiliza una propiedad automática no se compila:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Compile-Time Error!
    } 

    public int Size{get; set;}
}

El error devuelto es " El objeto 'this' no se puede usar antes de que todos sus campos se asignen a " ;. Sé que este es un procedimiento estándar para una estructura: el campo de respaldo para cualquier propiedad debe asignarse directamente (y no a través del conjunto de accesores de la propiedad) desde el constructor de la estructura.

Una solución es utilizar un campo de respaldo explícito:

struct MyStruct
{ 
    public MyStruct(int size)
    {
        _size = size;
    }

    private int _size;

    public int Size
    {
        get { return _size; }
        set { _size = value; }
    }
}

(Tenga en cuenta que VB.NET no tendría este problema, porque en VB.NET todos los campos se inicializan automáticamente a 0 / nulo / falso cuando se crean por primera vez).

Esto parece ser una limitación desafortunada cuando se usan propiedades automáticas con estructuras en C #. Pensando conceptualmente, me preguntaba si este no sería un lugar razonable para que exista una excepción que permita llamar al descriptor de acceso a conjunto de propiedades dentro del constructor de una estructura, al menos para una propiedad automática.

Este es un problema menor, casi un caso extremo, pero me preguntaba qué pensaban los demás sobre esto ...

¿Fue útil?

Solución

De C # 6 en adelante: esto ya no es un problema


En C # 6, debe llamar al constructor predeterminado para que esto funcione:

public MyStruct(int size) : this()
{
    Size = size;
}

Un problema más grande aquí es que tienes una estructura mutable. Esto es nunca una buena idea. Yo lo haría:

public int Size { get; private set; }

No es técnicamente inmutable, pero lo suficientemente cerca

Con las versiones recientes de C #, puedes mejorar esto:

public int Size { get; }

Esto ahora puede solo asignarse en el constructor.

Otros consejos

Puede solucionar esto llamando primero al constructor predeterminado:

struct MyStruct 
{
    public MyStruct(int size) : this() 
    {
        this.Size = size; // <-- now works
    }

     public int Size { get; set; }
}

Otra solución oscura a este problema es una que se encuentra en la clase Tuple temporal en la Marco de extensibilidad gestionado (a través de Krzysztof Ko & # 378; mic ):

public struct TempTuple<TFirst, TSecond>
{
    public TempTuple(TFirst first, TSecond second)
    {
        this = new TempTuple<TFirst, TSecond>(); // Kung fu!
        this.First = first;
        this.Second = second;
    }

    public TFirst First { get; private set; }
    public TSecond Second { get; private set; }

(Código fuente completo de Codeplex: Tuple.cs )

También observo que la documentación para CS0188 se ha actualizado a añadir:

  

Si ve este error al intentar   Inicializar una propiedad en una estructura.   Constructor, la solución es cambiar.   el parámetro constructor para especificar   el campo de apoyo en lugar de la   propiedad en sí. Implementado automáticamente   propiedades deben ser evitadas en   Estructuras porque no tienen respaldo.   campo y por lo tanto no puede ser   inicializado de alguna manera desde el   constructor.

Así que entiendo que la guía oficial es usar propiedades de estilo antiguo en tus estructuras cuando te encuentres con este problema, que probablemente sea menos oscuro (y más legible) que cualquiera de las otras dos alternativas exploradas, por lo que lejos.

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