Estoy codificando con un patrón de estado para un dispositivo incrustado. Tengo una clase base / abstracta llamada Estado y luego cada clase de estado discreta (concreta) implementa la Clase de estado abstracta.
En la clase de estado tengo varios métodos abstractos. Si no implemento los métodos abstractos en la clase discreta (concreta), Visual Studio dará un error similar a este:
... El error 1 'myConcreteState' no implementa el miembro abstracto heredado 'myAbstractState'
Ahora: estoy tratando de crear una propiedad de cadena para cada estado llamada StateName. Cada vez que creo una nueva clase concreta, necesito definir StateName. Quiero que VS arroje un error si no lo uso. ¿Hay una manera simple de hacer esto?
He intentado esto en la clase abstracta / base:
public abstract string StateName { get; set; }
Pero no necesito implementar los métodos Get y Set en cada estado.
Pregunta revisada: en una situación ideal, se requeriría que cada clase de estado tenga StateName define y se herede de la clase base abstracta.
StateName = "MyState1"; //or whatever the state's name is
Si falta esa declaración, Visual Studio generará un error como se describió anteriormente. ¿Es posible? y si lo es, cómo?
Respuestas:
Supongo que la forma "correcta" de hacer esto es tener un constructor protegido en la clase base que requiera el nombre del estado como parámetro.
Los estados concretos proporcionan un constructor público que llama implícitamente al constructor de la clase base con el nombre apropiado.
Como la clase base no expone ningún otro constructor (ni protegido ni público), cada clase heredada debe pasar por este único constructor y, por lo tanto, debe definir un nombre.
Tenga en cuenta que no necesita proporcionar el nombre cuando crea una instancia de un estado concreto porque su constructor se encarga de eso:
fuente
...:base(arg1, arg2)
! Esta es una solución que estaba buscando. Esto realmente ayuda a mantener mi codificación de estado más coherente.A partir de C # 6 (creo - C #: El nuevo y mejorado C # 6.0 ) puede crear propiedades solo getter. Entonces podrías declarar tu clase base de esta manera:
Y luego, en su subclase, puede implementar
State
así:O incluso más ordenado con el operador lambda:
Ambos siempre devolverán "Estado_1" y serán inmutables.
fuente
public override string name { get; } = "State_1";
lo que no necesita reevaluar el valor cada vez.Sus requisitos son una contradicción:
vs.
No hay una función de lenguaje que le permita forzar la existencia de un miembro en solo unas pocas subclases. Después de todo, el objetivo de utilizar una superclase es confiar en el hecho de que todas las subclases tendrán todos los miembros de la superclase (y posiblemente más). Si desea crear clases que actúen como un
State
pero no tengan un nombre, entonces, por definición, no deberían (/ pueden) ser subclases deState
.Tiene que cambiar sus requisitos o usar algo que no sea simple herencia.
Una posible solución con el código tal como es podría ser hacer que el método
State
no sea abstracto y devolver una cadena vacía.fuente
StateName = "MyState1"
en cada estado. Si no tengo esa declaración en la clase de estado, idealmente Visual Studio generará un error.return "MyState1"
como su implementación, y puede agregar almacenamiento mutable para el valor si lo necesitan. Pero debe aclarar los requisitos de la pregunta: ¿cada tipo de estado requiere un StateName que se pueda leer, y cualquier tipo de estado requiere que se mute después de la creación?