2010-01-08 22 views
9

¿Cuál es la mejor manera de inicializar constantes u otros campos en clases heredadas? Me doy cuenta de que hay muchos errores de sintaxis en este ejemplo, pero este es el mejor ejemplo para explicar claramente lo que estoy tratando de hacer.Inicializando campos en clases heredadas

public abstract class Animal { 
    public abstract const string Name; // #1 
    public abstract const bool CanFly; 
    public abstract double Price; // price is not const, because it can be modified 

    public void Fly() { 
    if (!CanFly) 
     Debug.Writeln("{0}s can't fly.", Name); 
    else 
     Debug.Writeln("The {0} flew.", Name); 
    } 
} 

public class Dog : Animal { 
    public override const string Name = "Dog"; // #2 
    public override const bool CanFly = false; 
    public override double Price = 320.0; 
} 

public class Bird : Animal { 
    public override const string Name = "Bird"; 
    public override const bool CanFly = true; 
    public override double Price = 43.0; 
} 

Un par de cosas que estoy tratando de lograr:

  • clases base deben asignar estos 3 campos.
  • Idealmente, me gustaría que estos campos inicializados estuvieran juntos en la parte superior de la clase para poder ver qué constantes asigné a cada clase y cambiarlas cuando sea necesario.
  • Los campos Nombre y CanFly no se pueden cambiar.

Sé que podría inicializar estos campos en un constructor (si se deshace de la const), pero no se garantiza que se asignarán. Si tiene estos campos como propiedades en su lugar y los reemplaza, aún deberá inicializar el campo de respaldo de la propiedad. ¿Cómo implementarías esto?

Unos pocos errores de sintaxis se queja:

  • El modificador 'abstracta' no es válido en los campos. Intenta usar una propiedad en su lugar. (# 1)
  • Un campo const requiere un valor que se proporciona (# 1)
  • El 'anulación' modificador no es válido para este elemento (# 2)
+3

Creo que estás entendiendo mal para qué son las constantes. Las constantes son para valores que nunca cambian a lo largo de la historia del universo; de ahí, el nombre "constante". Buenos ejemplos de constantes: el número de huevos en una docena, el número atómico de plomo. Malo: el número de versión de su aplicación; esto cambia con el tiempo Terrible: el precio del barril de petróleo; cambia cada pocos segundos. Si hay un campo cuyo valor puede cambiar durante el tiempo de vida de su aplicación, no es una constante. –

+0

Gracias por la explicación. Creo que estaba un poco confundido porque los campos Dog.Name y Dog.CanFly nunca deberían cambiarse, por lo tanto, creo que deberían ser constantes. Sin embargo, los campos Animal.Name y Animal.CanFly se cambiarán por clases heredadas, por lo que no deberían ser constantes. Intenté definirlos como constantes solo en clases heredadas, lo que supongo que no puedes hacer. – Senseful

+0

Para modelar un valor que se establece una vez en el momento de la construcción y nunca más después, use un campo de solo lectura. Los campos de solo lectura pueden ser campos de instancia, en cuyo caso puede tener un valor diferente para cada instancia, o estáticos, en cuyo caso cada instancia comparte el mismo valor. –

Respuesta

19

Si una clase base requiere un valor que debe ser proporcionada por una clase derivada, las dos formas más comunes son:

lo requieran en el constructor:

public readonly double Price; 

protected BaseClass(double price) 
{ 
    this.Price = price; 
} 

clases derivadas deben pasar el precio en el constructor:

public Derived() : base(32) 
{ 
} 

O, hacen es una propiedad abstracta:

public abstract double Price { get; } 

Las clases derivadas deben proporcionar alguna forma de devolver el valor (aunque donde consiguen que depende de la clase derivada, que en muchos casos proporciona una mayor flexibilidad):

public override double Price 
{ 
    get 
    { 
     return 32; 
    } 
} 
+1

La desventaja potencial de una propiedad abstracta es que las clases derivadas pueden romper la garantía de "nunca cambia durante la vida", que se puede aplicar con readonly field + ctor. –

5

Si usted quiere tener especial campos en su clase abstracta, pero no desea definirlos en la clase base, puede requerir que los implementadores suministren los valores a través del constructor.

public abstract class MyClass 
{ 
    private readonly double price; 

    protected MyClass(double price) 
    { 
     this.price = price 
    } 
} 

Con una clase tal base, todas las clases derivadas mosto suministran un valor al constructor de la clase de base, o el código no se compilará. Aquí está un ejemplo de cómo podría mirar:

public class Foo : MyClass 
{ 
    public Foo() : base(42) { } 
} 
1

Puede usar readonly y un constructor internal para aplicar este comportamiento, pero faltaría algo de finese.Si sigue así, los herederos deberían estar en el mismo espacio de nombres/ensamblado para aprovechar el constructor interno.

0

el otro modelo es crear un acceso (propiedad) que sea virtual. Esto obliga a las clases derivadas a implementarlo.

La ventaja de esto es que 'canfly' puede tener una respuesta que depende de la (por ejemplo) hora del día.

1

Los errores que recibe le dicen más o menos lo que debe hacer. Desea utilizar propiedades abstractas, no campos, para Name y CanFly, mientras que Price sería una propiedad normal. En las clases derivadas, las propiedades abstractas serían de solo lectura y devolverían una constante, en cada caso. En el código:

public abstract class Animal { 
    public abstract string Name { get; } 
    public abstract bool CanFly { get; } 
    public double Price { get; set; } 
    // etc 
} 

public class Dog : Animal { 
    public override string Name { get { return "Dog"; } } 
    public override bool CanFly { get { return false; } } 
    public Dog() { Price = 320.0; } 
} 

// etc 
Cuestiones relacionadas