2012-07-13 20 views
5

Por el bien de este ejemplo, supongamos que estamos haciendo un juego tonto de Clue ™. Tenemos una clase para cada habitación de la mansión y subclases para el sospechoso y el arma en cada habitación. Algo así como:Un constructor para una clase y sus clases anidadas

class Room 
{ 
    public string Name; 
    public int Width; 
    public int Height; 
    // and so on... 

    public class Suspect 
    { 
    public string Name; 
    public bool isPurple; 
    } 

    public class Weapon 
    { 
    public string Name; 
    public bool IsMetal; 
    } 
} 

Antes de añadir las clases sospechoso y Arma, el constructor habitación parecía algo así como:

public Room(string Name, int Width, int Height) 
{ 
    this.Name = Name; 
    this.Width = Width; 
    this.Height = Height; 
} 

la inicialización de una habitación que solía ser tan simple como: Room[i] = new Room("Conservatory", 7, 3); - pero después de las clases anidadas eran introducido, ¿su inicialización puede manejarse a través de un constructor compartido con la clase principal? Algo como:

Room[i] = new Room("Library", 8, 5, "Professor Plum", true, "Candlestick", true); 

No puedo encontrar ningún ejemplo de una configuración similar. ¿Cómo puedo lograr esto?

+0

¿Está buscando algo como esto ParentClass.ChildClass childClass = new ParentClass.ChildClass(); – HatSoft

+7

Una clase anidada no tiene una relación particular con su clase principal. Excepto que puedes declararlo privado y así esconderlo por completo. Y que puede acceder a miembros privados de la clase externa. Eso es todo, no hay ningún escenario en el que un "constructor compartido" tenga sentido. Tampoco tiene sentido hacer que la clase de personaje sea un detalle de implementación privada de una habitación. –

+0

No encuentra ningún ejemplo porque ninguno podría escribir un ejemplo para eso, ¿cómo puede el compilador saber que "Profesor Plum" se debe usar como valor para la propiedad Suspect.Name? (Supongo que esta es tu intención) – Steve

Respuesta

7

En lugar de tener su constructor con tantos parámetros, ¿por qué no hacer algo como esto?

public class Room 
{ 
    public Room(Suspect suspect, Weapon weapon) 
    { 
     SuspectInRoom = suspect; 
     WeaponInRoom = weapon; 
    } 

    public Suspect SuspectInRoom { get; set; } 
    public Weapon WeaponInRoom { get; set; } 
} 

// Example usage: 

Suspect coronelCustard = new Suspect("Coronel Custard"); 
Weapon musket = new Weapon("Musket"); 

Room someRoom = new Room(coronelCustard, musket); 

// Then your room can be used to access all sorts of data. 

Console.WriteLine(someRoom.SuspectInRoom.Nickname); // "The Big Kahuna" 
Console.WriteLine(someRoom.WeaponInRoom.AttackDamage); // "20" 

Cuando las clases anidadas se introducen a una clase principal, puede su inicialización ser manejados a través de un constructor compartido con la clase principal ? Con el tiempo me espero para inicializar las tres clases en la misma línea ...

Si su clase anidada tiene un constructor público que puede hacer eso.

Ejemplo:

Room someRoom = new Room(new Suspect("Colonel Custard"), new Weapon("Musket")); 

embargo, es un poco de un olor código para hacer las cosas de esta manera. Es mejor usar miembros ya creados e instanciados en llamadas de constructor. Es una elección personal de cualquier manera.

+0

+1. pero recuerde que en su código, una Sala no puede tener nombre, que no era el caso con el constructor de OP. – ken2k

+0

@ ken2k: Ah, sí, tendría que ajustar esto a sus necesidades. Quiero ilustrar cómo organizar mejor sus clases. –

+1

Nunca he jugado una versión de Clue en la que el "daño de ataque" de un arma sea importante. Después de todo, el único "atacado" está muerto al comienzo del juego. ;) –

5

Ni siquiera necesita constructores ... sólo tiene que utilizar los inicializadores:

var room = new Room { Name = "Library", 
         Width = 7, 
         Height = 3, 
         Suspect = new Suspect { Name = "Professor Plum", 
               PlaysCroquet = false }, 
         Weapon = new Weapon { Name = "Candlestick", 
               IsShiny = true } 
         }; 
+0

Sospechoso y Arma no son campos en su ejemplo, son clases anidadas. –

+1

¡me robaste la idea! ;) –

+0

La metáfora se vino abajo un poco - la razón por la que estaba usando el constructor fue para la aleatorización futura de los campos. La profesora Plum no necesariamente va a la Biblioteca. – 4444

2

Una forma sencilla de hacerlo es dar el sospechoso y clases de armas constructores públicos, por lo que se pueden crear instancias fuera del la clase Room (supongo que esto es aceptable, ya que las clases se declaran públicas).

El constructor de la sala puede entonces hacer referencia a un sospechoso y un arma. Esto te da la flexibilidad de crear objetos sospechosos y armas en algún punto anterior, y pasarlos a una sala en construcción; también evita que el constructor de la clase sala tenga que conocer las propiedades de las clases sospechosas y armas (y requerir modificaciones cuando agregar a ellos).

Por razones de brevedad, todavía se puede construir todos los objetos en una sola línea, así:

Room[i] = new Room("Library", 8, 5, new Suspect("Professor Plum", false), new Weapon("Candlestick", true)); 
1

Clases por sí mismos no necesitan ser inicializado, son miembros.

No existen restricciones formales sobre qué argumentos pasa al constructor y qué miembros de la clase inicializa en el constructor.Si el tipo de campos o propiedades pasan a ser clases anidadas, no es diferente de int o string desde el punto de vista del constructor *.

*: La única diferencia potencial es que los miembros del tipo de clases anidadas no públicas deben inicializarse en algún otro método o constructor, a diferencia de las propiedades públicas de lectura/escritura que también se pueden establecer directamente en la instancia de la clase.

Cuestiones relacionadas