2010-12-02 11 views
10

Por favor explique el siguiente error en struct constructor. Si cambio la estructura a la clase , los errores han desaparecido.Error de compilación. Usar propiedades con struct

public struct DealImportRequest 
{ 
    public DealRequestBase DealReq { get; set; } 
    public int ImportRetryCounter { get; set; } 

    public DealImportRequest(DealRequestBase drb) 
    { 
     DealReq = drb; 
     ImportRetryCounter = 0; 
    } 
} 
  • CS0188 de error: El 'esto' objeto no puede ser utilizado antes de que todos sus campos se asignan a CS0843
  • error: Copia de campo para la propiedad 'DealImportRequest.DealReq' implementado de forma automática debe estar completamente asignado antes de que se devuelva el control a la persona que llama. Considere llamar al constructor predeterminado desde un inicializador de constructor.
+0

Posible duplicado de http://stackoverflow.com/questions/2534960/c-struct-constructor-fields-must-be-fully-assigned-before-control-is-returned – Hps

+0

@Hps, no estoy de acuerdo. Si bien se relaciona con el mismo problema que en esa pregunta, el hecho de que hacerlo en relación con un campo implícito (respaldar la propiedad automática) en lugar de uno explícito podría ser suficiente para evitar que alguien vea por qué se relacionan estas dos preguntas. Eso debería ser suficiente para considerar que no duplican la IMO. –

+0

Tiene razón. Gracias por la explicación. Debería ser más cuidadoso :) – Hps

Respuesta

14

Como lo recomienda el mensaje de error, puede resolver esto llamando al constructor predeterminado desde un inicializador de constructor.

public DealImportRequest(DealRequestBase drb) : this() 
{ 
    DealReq = drb; 
    ImportRetryCounter = 0; 
} 

De la especificación del lenguaje:

10.7.3 propiedades implementadas automáticamente

Cuando una propiedad se especifica como una propiedad de forma automática implementado, un campo oculto respaldo es automáticamente disponible para la propiedad, y los accesorios son implementados para leer de y escriba en ese campo de respaldo. [...] Dado que el campo de respaldo es inaccesible, puede leerse y escribirse únicamente a través de los descriptores de acceso de propiedad , incluso dentro del tipo que contiene . [...] Esta restricción también significa que definitiva asignación de tipos struct con propiedades de auto-aplicado sólo puede puede lograr utilizando el estándar constructor de la estructura, desde asignando a la propiedad en sí requiere la struct a ser definitivamente asignado. Esto significa que los constructores definidos por el usuario deben llamar al constructor predeterminado .

La otra alternativa (más detallada), por supuesto, es implementar manualmente las propiedades y establecer los campos de respaldo en el constructor.

Tenga en cuenta que la estructura que tiene allí es mutable. This is not recommended. Sugiero que hagas del tipo una clase (tus problemas de compilación desaparecerán inmediatamente) o que el tipo sea inmutable. La manera más fácil de lograr esto, suponiendo que el código que ha presentado es el estructura completa, sería hacer los instaladores privados (get; private set;). Por supuesto, también debe asegurarse de no agregar ningún método de mutación a la estructura posterior que dependa del acceso privado para modificar los campos. Alternativamente, puede respaldar las propiedades con los campos de respaldo readonly y deshacerse de los incubadores por completo.

+0

Yeap. Me acabo de dar cuenta de que no es bueno para mí. –

3

El código que se tiene es equivalente al código siguiente:

public struct DealImportRequest 
{ 
    private DealRequestBase _dr; 
    private int _irc; 
    public DealRequestBase DealReq 
    { 
     get { return _dr; } 
     set { _dr = value; } 
    } 
    public int ImportRetryCounter 
    { 
     get { return _irc; } 
     set { _irc = value; } 
    } 
    /* Note we aren't allowed to do this explicitly - this is didactic code only and isn't allowed for real*/ 
    public DealImportRequest() 
    { 
     this._dr = default(DealRequestBase); // i.e. null or default depending on whether this is reference or value type. 
     this._irc = default(int); // i.e. 0 
    } 
    public DealImportRequest(DealRequestBase drb) 
    { 
     this.DealReq = drb; 
     this.ImportRetryCounter = 0; 
    } 
} 

Ahora, todo lo que he hecho aquí es quitar el azúcar sintáctica que:

  1. Implementa propiedades automáticas.
  2. Resuelve qué miembros se tratan en relación con this.
  3. Otorga a todos struct s un constructor sin parámetro predeterminado.

Los dos primeros son opcionales (se podría escribir de forma explícita si hubiese deseado), pero el tercero no es - no se nos permite escribir nuestro propio código para un struct 's constructor sin parámetros, tenemos que ir con uno que funciona como el del código anterior que se nos da automáticamente.

Ahora, aquí se ve claramente el significado de los dos errores: el constructor usa implícitamente this antes de asignar los campos (error 188) y esos campos son los que respaldan las propiedades automáticas (error 843).

Es una combinación de diferentes funciones automáticas que normalmente no tenemos que pensar, pero en este caso no funcionan bien. Podemos solucionar este problema siguiendo los consejos en el mensaje de error para 843 y llamar al constructor por defecto como parte de su constructor explícito:

public DealImportRequest(DealRequestBase drb) 
    :this() 
{ 
    DealReq = drb; 
    ImportRetryCounter = 0; 
} 

Teniendo en cuenta esto en relación con mi versión ampliada de su código anterior, se puede ver cómo esto resuelve el problema, ya que llama al constructor que asigna los campos de respaldo antes de que proceda.

0

Recomendaría no utilizar auto-propiedades con estructuras a menos que tenga un buen motivo para usarlas. Envolver un campo de clase en una propiedad de lectura-escritura es útil porque permite que una instancia controle las circunstancias en las que puede leerse o escribirse, y tomar medidas cuando tiene lugar una lectura o escritura. Además, el código dentro de una instancia de objeto puede identificar la instancia sobre la que se actúa y, por lo tanto, puede realizar una acción especial solo cuando lee y escribe una instancia particular. El uso de una propiedad automática en una versión anterior de una clase permitirá que las versiones futuras de la clase utilicen una propiedad implementada manualmente, incluidas las ventajas antes mencionadas, a la vez que conserva la compatibilidad con el código de cliente ya compilado. Desafortunadamente, envolver un campo de estructura en una propiedad de lectura-escritura no ofrece los mismos beneficios porque los campos de una instancia de estructura pueden copiarse a otro sin que ninguna instancia tenga voz en el asunto. Si la semántica de una estructura permite que una propiedad se escriba con valores arbitrarios en la mayoría de las instancias [como sería el caso de una propiedad automática], entonces cualquier sustitución legítima sería semánticamente equivalente a un campo.

Cuestiones relacionadas