2011-11-16 45 views
12

Tengo un struct que contiene dos listas:¿Hay alguna forma de inicializar miembros de una estructura sin usar un constructor?

struct MonthData 
{ 
    public List<DataRow> Frontline; 
    public List<DataRow> Leadership; 
} 

Sin embargo, quiero inicializar tanto cuando se crea la estructura. Si trato:

struct MonthData 
{ 
    public List<DataRow> Frontline = new List<DataRow>(); 
    public List<DataRow> Leadership = new List<DataRow>(); 
} 

Entonces me sale:

Error 23 'MonthData.Frontline': cannot have instance field initializers in structs 
... 

Desde estructuras no pueden tener constructores sin parámetros, que no puedo acaba de establecer esto en un constructor tampoco. Hasta el momento, sólo puedo ver las siguientes opciones:

  1. inicializar las propiedades cuando se crea una instancia de MonthData
  2. utilizar una clase en lugar de una estructura
  3. Crear un constructor con un parámetro y el uso que
  4. Hacer getters y setters para las propiedades que los inicializan perezosamente.

¿Cuál es el método recomendado para esto? En este momento, estoy pensando que hacer de esto una clase es la mejor idea.

+0

Haz que sea una clase. Una vez que agrega tipos de referencia a una estructura, ya no es un tipo de valor. – drdwilcox

+1

¿Está realmente bien hacer que sea un tipo de referencia (clase) frente a un tipo de valor (struct)? Si es así, adelante y conviértalo en una clase. – BoltClock

+0

Sí, no tiene sentido que este tipo sea una estructura. –

Respuesta

7

Debería usar una clase en su lugar. De MSDN:

En general, las clases se utilizan para modelar comportamientos más complejos, o datos que se pretende modificar después de crear un objeto de clase. Las estructuras son más adecuadas para estructuras de datos pequeñas que contienen principalmente datos que no están destinados a modificarse una vez creada la estructura.

1

No hay forma de hacerlo con un constructor. El CLR puede y creará instancias de estructuras simplemente siendo cero inicializando la memoria y evitando cualquier sobrecarga del ctor. Sin embargo, puede aprovechar este conocimiento y crear propiedades inicializadas de retraso que tienen el mismo efecto observable.

Por ejemplo:

struct MonthData { 
    private bool m_initialized; 
    private List<DataRow> m_frontLine; 
    private List<DataRow> m_leaderShip; 

    public List<DataRow> FrontLine { 
    get { 
     EnsureInitialized(); 
     return m_frontLine; 
    } 
    } 

    public List<DataRow> LeaderShip { 
    get { 
     EnsureInitialized(); 
     return m_leaderShip; 
    } 
    } 

    void EnsureInitialized() { 
    if (!m_initialized) { 
     m_initialized = true; 
     m_frontLine = new List<DataRow>(); 
     m_leaderShip = new List<DataRow>(); 
    } 
    } 
} 
+0

Sí, creo que hacer algo como esto sería mi segunda opción. Pero es un objeto tan simple, tiendo a estar de acuerdo con otros aquí y creo que esto debería ser solo una clase, especialmente porque solo contiene dos tipos de referencia. –

+1

@MikeChristensen en general sí, probablemente debería ser una clase. Mi respuesta es más de "si te quedas atascado en una esquina y tienes que usar una estructura, haz esto" – JaredPar

+0

Sí, creo que el enfoque de fábrica y el enfoque de inicialización perezosa son geniales. Lo tendré en cuenta para futuros desafíos de diseño . –

6

Si acaba de preguntar sobre la sintaxis ... intenta construir y usar una fábrica estático en lugar ... En general, las estructuras se debe utilizar para las cosas que son inmutables, y una fábrica, (que llama a un constructor privado) es un mejor enfoque para un tipo inmutable que el uso de un constructor público.

struct MonthData 
    {  
     public List<DataRow> Frontline; 
     public List<DataRow> Leadership; 
     private MonthData(List<DataRow> frontLine = null, 
         List<DataRow> leadership = null) 
     { 
     Frontline = frontLine?? new List<DataRow>(); 
     Leadership = leadership?? new List<DataRow>(); 
     } 
     public static MonthData Factory(
      List<DataRow> frontLine= null, 
      List<DataRow> leadership= null) 
     { return new MonthData(frontLine, leadership); } 
    } 
+0

Este es un enfoque interesante. Como mencionaste, mi objetivo no es inmutable (es más una colección donde todo se agregará a todo) su vida) así que tal vez una clase es la mejor. +1 para la idea. –

+0

Me gusta la idea del método de fábrica estático. No tiene inicializadores de campo de instancia en estructuras. Entonces 'público List FrontLine = new List ()' no se va a compilar. –

+0

@Jim Mis, sí, cortar y pegar sin editar ... lo corrigió ... –

6

Estás usando los tipos de referencia (List<T>) en su estructura de todos modos, por lo tanto el uso de una estructura como tipo de valor no tendría ningún sentido para mí. Solo iría con una clase.

+0

Otra alternativa sería usar 'ImmutableArray ' y seguir con el método de creación mencionado por @CharlesBretana. – m93a

1

Hubiera sido agradable si el CLR había permitido un medio para garantizar que las cosas de tipo de estructura podría tener algún código de inicialización se ejecutan en ellos antes de que se hicieron visibles a cualquier cosa fuera de dicho código. Hubiera sido posible hacer eso, incluso al crear una matriz de un tipo de estructura, haciendo que el CLR pase por referencia todos los elementos individuales de la matriz antes de que una referencia a la misma matriz quedara expuesta en cualquier lugar. Desafortunadamente, habría llevado a una situación incómoda si se hubiera lanzado una excepción durante la creación de la matriz.Si los constructores no tuvieran ningún efecto secundario, no habría ningún problema, simplemente descartar la matriz y pretender que incluso los objetos creados con éxito nunca existieron. Los constructores con efectos secundarios, sin embargo, podrían causar algunas dificultades.

Como lo es, sin embargo, no hay forma de inicializar las estructuras en la construcción y, en consecuencia, no hay una buena forma de lograr la semántica del tipo de valor con los objetos que requieren inicialización. Lo siento. Incluso si la semántica del tipo de valor fuera más apropiada para su tipo (como sería el caso con mucha más frecuencia de lo que algunos creerían), tendrá que usar un tipo de referencia si la inicialización es necesaria. La inicialización lenta de las estructuras realmente no funciona. Por ejemplo, si uno tiene un Dictionary < String, MonthData > llamado MyDict, accesos repetidos a MyDict ("George"). FrontLine generaría cada uno una nueva lista. Asqueroso.

Las estructuras mutables no son malas; Soy, en todo caso, uno de sus defensores más fuertes. No obstante, hay algunas limitaciones en el manejo de .NET de las estructuras mutables, y existen muchas circunstancias en las que la semántica de tipo de valor sería apropiada, pero las limitaciones de .NET hacen que sea imposible proporcionar dicha semántica de manera adecuada.

Cuestiones relacionadas