2008-11-28 13 views
113

Tengo una clase base abstracta y deseo declarar un campo o una propiedad que tendrá un valor diferente en cada clase que herede de esta clase principal.Reemplazando campos o propiedades en subclases

Quiero definirlo en la clase base para que pueda referenciarlo en un método de clase base, por ejemplo anulando ToString para decir "Este objeto es del tipo propiedad/campo". Tengo tres formas de hacerlo, pero me preguntaba: ¿cuál es la forma mejor o más aceptada de hacer esto? Pregunta de novato, lo siento

Opción 1:
uso de una propiedad de abstracta y anular en las clases heredadas. Esto se ve reforzado (tiene que anularlo) y está limpio. Sin embargo, se siente un poco mal devolver un valor de código duro en lugar de encapsular un campo y se trata de unas pocas líneas de código en lugar de solo. También tengo que declarar un cuerpo para "establecer", pero eso es menos importante (y probablemente haya una forma de evitar aquello de lo que no tengo conocimiento).

abstract class Father 
{ 
    abstract public int MyInt { get; set;} 
} 

class Son : Father 
{ 
    public override int MyInt 
    { 
     get { return 1; } 
     set { } 
    } 
} 

Opción 2
puedo declarar un campo público (o un campo protegido) y explícitamente anularlo en la clase heredada. El siguiente ejemplo me dará una advertencia para usar "nuevo" y probablemente pueda hacer eso, pero se siente mal y rompe el polimorfismo, que fue el punto. No me parece una buena idea ...

abstract class Mother 
{ 
    public int MyInt = 0; 
} 

class Daughter : Mother 
{ 
    public int MyInt = 1; 
} 

Opción 3
puedo usar un campo protegido y establecer el valor en el constructor. Esto parece bastante ordenado, pero confío en que me asegure de que el constructor siempre establezca esto y con múltiples constructores sobrecargados siempre hay una posibilidad de que alguna ruta de código no establezca el valor.

abstract class Aunt 
{ 
    protected int MyInt; 
} 

class Niece : Aunt 
{ 
    public Niece() 
    { 
     MyInt = 1; 
    } 
} 

Es un poco de una cuestión teórica y supongo que la respuesta tiene que ser la opción 1, ya que es la única opción segura pero yo soy más que llegar a enfrentarse con C# y quería preguntar esto de las personas con más experiencia.

Respuesta

107

De las tres soluciones solamente Opción 1 es polimórfica .

Los campos por sí solos no pueden anularse. Que es exactamente por qué Opción 2 devuelve el nuevo advertencia de palabra clave.

La solución a la advertencia no es para anexar la “nueva” palabra clave, pero para poner en práctica la opción 1.

Si necesita que su campo para ser polimórficos que necesita para envolverlo en una propiedad.

Opción 3 es correcto si no necesita un comportamiento polimórfico. Sin embargo, debe recordar que cuando en el tiempo de ejecución se accede a la propiedad MyInt, la clase derivada no tiene control sobre el valor devuelto. La clase base en sí misma es capaz de devolver este valor.

Así es como podría verse una implementación verdaderamente polimórfica de su propiedad, permitiendo que las clases derivadas estén en el control .

abstract class Parent 
{ 
    abstract public int MyInt { get; } 
} 

class Father : Parent 
{ 
    public override int MyInt 
    { 
     get { /* Apply formula "X" and return a value */ } 
    } 
} 

class Mother : Parent 
{ 
    public override int MyInt 
    { 
     get { /* Apply formula "Y" and return a value */ } 
    } 
} 
+104

Como un aparte, realmente creo que el ** Padre ** debe aplicar la fórmula "Y", y la Madre, lógicamente, "X". –

0

Iría con la opción 3, pero tengo un método setMyInt abstracto que las subclases están obligadas a implementar. De esta forma, no tendrás el problema de que una clase derivada olvide establecerlo en el constructor.

abstract class Base 
{ 
protected int myInt; 
protected abstract void setMyInt(); 
} 

class Derived : Base 
{ 
override protected void setMyInt() 
{ 
    myInt = 3; 
} 
} 

Por cierto, con la opción uno, si no especifica establecer; en su propiedad de clase base abstracta, la clase derivada no tendrá que implementarla.

abstract class Father 
{ 
    abstract public int MyInt { get; } 
} 

class Son : Father 
{ 
    public override int MyInt 
    { 
     get { return 1; } 
    } 
} 
0

Usted puede ir con la opción 3 si modifica su clase base abstracta para exigir al valor de la propiedad en el constructor, que no se pierda ninguna ruta. Realmente consideraría esta opción.

abstract class Aunt 
{ 
    protected int MyInt; 
    protected Aunt(int myInt) 
    { 
     MyInt = myInt; 
    } 

} 

Por supuesto, entonces todavía tienen la opción de hacer el campo privado y luego, dependiendo de la necesidad, la exposición de una propiedad de captador protegida o pública.

3

se podría definir algo como esto:

abstract class Father 
{ 
    //Do you need it public? 
    protected readonly int MyInt; 
} 

class Son : Father 
{ 
    public Son() 
    { 
     MyInt = 1; 
    } 
} 

Al establecer el valor como de sólo lectura, se garantiza que el valor de esa clase se mantiene sin cambios durante toda la vida del objeto.

Supongo que la siguiente pregunta es: ¿por qué la necesitas?

+0

Static es una mala elección de palabras ya que implica que el valor se comparte entre todas las instancias de la clase, lo que por supuesto no es así. –

+0

Eso es verdad. Lo editaré. – Ant

15

Opción 2 es un no-arrancador - se puede no anulación campos, sólo se puede ocultar ellos.

Personalmente, iría por la opción 1 todo el tiempo. Intento mantener los campos privados en todo momento. Eso es si realmente necesita poder anular la propiedad, por supuesto. Otra opción es tener una propiedad de sólo lectura en la clase base que se fija un parámetro de constructor:

abstract class Mother 
{ 
    private readonly myInt; 
    public int MyInt { get { return myInt; } } 

    protected Mother(int myInt) 
    { 
     this.myInt = myInt; 
    } 
} 

class Daughter : Mother 
{ 
    public Daughter() : base(1) 
    { 
    } 
} 

Eso es probablemente el método más apropiado si el valor no cambia durante la vida de la instancia.

+0

¿Podemos decir que esto ahora no es correcto basado en este http://msdn.microsoft.com/en-us/library/9fkccyh4.aspx? El artículo msdn muestra que puede anular las propiedades – codingbiz

+1

@codingbiz: ¿dónde habla mi respuesta acerca de las propiedades? Los campos y las propiedades no son lo mismo. –

+0

@codingbiz: (Mi respuesta * ahora * habla sobre propiedades, hay que admitirlo, pero nunca dijo que no podrías anularlas. Dijo, y dice, que no puedes anular * campos *, lo cual sigue siendo correcto). –

6

opción 2 es una mala idea. Dará lugar a algo llamado sombreado; Básicamente tiene dos miembros "MyInt" diferentes, uno en la madre y el otro en la hija. El problema con esto es que los métodos que se implementan en la madre harán referencia al "MyInt" de la madre, mientras que los métodos implementados en la hija harán referencia al "MyInt" de la hija. esto puede causar problemas graves de legibilidad y confusión más adelante.

Personalmente, creo que la mejor opción es 3; ya que proporciona un valor centralizado clara, y se puede hacer referencia internamente por los niños sin la molestia de definir sus propios campos - que es el problema con la opción 1.

3

Usted puede hacer esto

class x 
{ 
    private int _myInt; 
    internal virtual int myInt { get { return _myInt; } set { _myInt = value; } } 
} 

class y : x 
{ 
    private int _myYInt; 
    public override int myInt { get { return _myYInt; } set { _myYInt = value; } } 
} 

virtual le permite obtener una propiedad de un cuerpo que hace algo y todavía permite subclases anularlo.

0

lo hice ...

namespace Core.Text.Menus 
{ 
    public abstract class AbstractBaseClass 
    { 
     public string SELECT_MODEL; 
     public string BROWSE_RECORDS; 
     public string SETUP; 
    } 
} 

namespace Core.Text.Menus 
{ 
    public class English : AbstractBaseClass 
    { 
     public English() 
     { 
      base.SELECT_MODEL = "Select Model"; 
      base.BROWSE_RECORDS = "Browse Measurements"; 
      base.SETUP = "Setup Instrument"; 
     } 
    } 
} 

De esta manera puede seguir utilizando campos.

+0

Siento que esto es agradable como una solución ad-hoc para prototipos o demo. – Zimano

Cuestiones relacionadas