Tengo una clase base abstracta y quiero declarar un campo o una propiedad que tendrá un valor diferente en cada clase que herede de esta clase principal.
Quiero definirlo en la clase base para poder hacer referencia a él en un método de clase base, por ejemplo, anulando ToString para decir "Este objeto es de tipo propiedad / campo ". Tengo tres formas de ver esto, pero me preguntaba: ¿cuál es la mejor forma aceptada de hacerlo? Pregunta de novato, lo siento.
Opción 1:
usar una propiedad abstracta y anularla en las clases heredadas. Esto se beneficia de su cumplimiento (debe anularlo) y está limpio. Pero, se siente un poco mal devolver un valor de código duro en lugar de encapsular un campo y son unas pocas líneas de código en lugar de solo. También tengo que declarar un cuerpo para "set", pero eso es menos importante (y probablemente haya una forma de evitar lo que no conozco).
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 anularlo explícitamente en la clase heredada. El siguiente ejemplo me dará una advertencia para usar "nuevo" y probablemente pueda hacerlo, pero se siente mal y rompe el polimorfismo, que era el punto central. No 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ía en mí para garantizar que el constructor siempre establezca esto y, con múltiples constructores sobrecargados, siempre existe la 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 una pregunta un poco teórica y supongo que la respuesta tiene que ser la opción 1, ya que es la única opción segura , pero me estoy familiarizando con C # y quería preguntarle esto a las personas con más experiencia.
fuente
Respuestas:
De las tres soluciones, solo la Opción 1 es polimórfica .
Los campos por sí mismos no pueden ser anulados. Por eso exactamente la Opción 2 devuelve la nueva advertencia de palabra clave.
La solución a la advertencia no es agregar la palabra clave "nueva", sino implementar la Opción 1.
Si necesita que su campo sea polimórfico, debe envolverlo en una Propiedad.
La opción 3 está bien si no necesita un comportamiento polimórfico. Sin embargo, debe recordar que cuando en tiempo de ejecución se accede a la propiedad MyInt, la clase derivada no tiene control sobre el valor devuelto. La clase base por 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 tengan el control .
fuente
La opción 2 no es un iniciador: no puede anular campos, solo puede ocultarlos .
Personalmente, iría por la opción 1 cada vez. Intento mantener los campos privados en todo momento. Eso si realmente necesita poder anular la propiedad, por supuesto. Otra opción es tener una propiedad de solo lectura en la clase base que se establece a partir de un parámetro constructor:
Ese es probablemente el enfoque más apropiado si el valor no cambia durante la vida útil de la instancia.
fuente
La opción 2 es una mala idea. Resultará en algo llamado sombreado; Básicamente tiene dos miembros diferentes de "MyInt", uno en la madre y el otro en la hija. El problema con esto es que los métodos implementados 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 algunos problemas serios de legibilidad y confusión más adelante.
Personalmente, creo que la mejor opción es 3; porque proporciona un valor centralizado claro y los niños pueden hacer referencia internamente sin la molestia de definir sus propios campos, que es el problema con la opción 1.
fuente
Podrías hacer esto
virtual le permite obtener una propiedad de un cuerpo que hace algo y aún permite que las subclases lo anulen.
fuente
Podrías definir algo como esto:
Al establecer el valor como de solo lectura, se garantiza que el valor de esa clase permanezca sin cambios durante la vida útil del objeto.
Supongo que la siguiente pregunta es: ¿por qué lo necesitas?
fuente
Si está creando una clase y desea que haya un valor base para la propiedad, utilice la
virtual
palabra clave en la clase base. Esto le permite anular opcionalmente la propiedad.Usando su ejemplo anterior:
En un programa:
fuente
Iría con la opción 3, pero tengo un método abstracto setMyInt que las subclases están obligadas a implementar. De esta forma, no tendrá el problema de que una clase derivada se olvide de configurarla en el constructor.
Por cierto, con la opción uno, si no especifica set; en su propiedad de clase base abstracta, la clase derivada no tendrá que implementarla.
fuente
Puede ir con la opción 3 si modifica su clase base abstracta para requerir el valor de la propiedad en el constructor, no se perderá ninguna ruta. Realmente consideraría esta opción.
Por supuesto, aún tiene la opción de hacer que el campo sea privado y luego, dependiendo de la necesidad, exponer a un comprador protegido o de propiedad pública.
fuente
Hice esto...
De esta manera, todavía puede usar campos.
fuente
La implementación de ejemplo cuando desea tener una clase abstracta con implementación. Las subclases deben:
En este caso, las propiedades que son necesarias para la implementación no deberían estar disponibles para su uso, excepto para la clase abstracta y su propia subclase.
fuente