c# - inherit - ¿Usando ''this'' en el constructor base?
this c# (4)
¿Su diseño distingue entre un juego (por ejemplo, backgammon) y un juego en curso (un juego de backgammon)? Si estás tratando de mezclar estos dos conceptos, te sugiero que los modeles por separado. Por ejemplo, Backgammon y BackgammonContest.
Estoy trabajando en un proyecto que implica una gran cantidad de interfaces y herencia, que están empezando a ser un poco complicadas, y ahora me he encontrado con un problema.
Tengo un estado de clase abstracto que toma un objeto Game como un argumento de constructor. En el constructor de mi clase de juego, toma en un estado. La idea es que cuando se hereda de la clase de juego base abstracta, cuando se llama al constructor de la clase base, se le asigna un objeto de estado inicial. Sin embargo, este objeto de estado toma el mismo juego en el que lo estás creando. El código se ve así:
public class PushGame : ManiaGame
{
public PushGame() :
base(GamePlatform.Windows, new PlayState(this), 60)
{
}
}
Sin embargo, esto no funciona. Solo puedo asumir que la palabra clave ''this'' no se puede usar hasta después de que el constructor haya comenzado a ejecutarse. Tratar de usarlo en el constructor de la clase base no funciona, al parecer. Entonces, ¿cuál sería mi mejor solución para esto? Mi plan B es simplemente eliminar el argumento de Estado del constructor de la clase de Juego y luego establecer el estado dentro del código del constructor.
¿Hay una manera más fácil y menos intrusiva de hacer esto?
Claramente, la clase ManiaGame siempre usa objetos del tipo PlayState, por lo que puede mover la creación al nivel ManiaGame:
public class PushGame : ManiaGame
{
public PushGame() : base()
{
}
}
public class ManiaGame
{
PlayState ps;
public ManiaGame() {
ps = new PlayState(this);
}
}
Si quieres más clases concretas de PlayState ...
public class PushGame : ManiaGame
{
public PushGame() : base()
{
}
protected override PlayState CreatePlayState()
{
return new PushGamePlayState(this);
}
}
public class ManiaGame
{
PlayState ps;
public ManiaGame() {
ps = CreatePlayState();
}
protected virtual PlayState CreatePlayState()
{
return new PlayState(this);
}
}
public class PlayState
{
public PlayState(ManiaGame mg) {}
}
public class PushGamePlayState : PlayState
{
public PushGamePlayState(ManiaGame mg) : base(mg){}
}
De la especificación de lenguaje C #
Un inicializador de constructor de instancia no puede acceder a la instancia que se está creando. Por lo tanto, es un error en tiempo de compilación hacer referencia a esto en una expresión de argumento del inicializador del constructor, ya que es un error en tiempo de compilación para que una expresión de argumento haga referencia a cualquier miembro de la instancia a través de un simple_name.
es decir, this
solo se puede utilizar para hacer referencia a otro constructor en el contexto de un inicializador de constructor, ya que la referencia a la instancia de objeto actual no estará disponible hasta que se complete la construcción.
es decir, this
solo se puede usar como una palabra clave de alcance antes de que el constructor ejecute:
: this("ParameterForAnotherConstructor")
Pero no está disponible como una referencia a la instancia de clase, ya que no ha completado la construcción.
: base(this) // Keyword this is not available in this context
Y, obviamente, tampoco podemos llamar a ningún método de instancia desde el inicializador del constructor
: base(GetThis()) // Object reference is required
Para resolver el problema de OP, los cambios en la clase base de Mania
parecen inevitables, dado el acoplamiento bidireccional entre PlayState
y ManiaGame
(o subclases de ManiaGame
, como PushGame
). Hay muchos patrones disponibles para desacoplar dependencias tan estrechas como esta, como el principal de inversión de dependencia (es decir, abstraer el acoplamiento entre las clases), o el patrón de observador (una de las dos clases genera eventos o permite enlazar devoluciones de llamada (por ejemplo, delegados o Action
s), permitiendo que la segunda clase "observe" los cambios de estado sin el acoplamiento duro entre ellos.
Hay una pregunta similar sobre Desbordamiento de pila, la palabra clave ''this'' (Me) no está disponible llamando al constructor base con una solución similar a su sugerencia.
Si la implementación del State
utilizada depende de la clase de Game
concreta, crearía una nueva instancia del State
dentro del constructor de la clase de Game
secundaria ( PushGame
) y PushGame
al State
en la clase base a través de la propiedad abstract
.
public class PushGame : ManiaGame
{
private readonly PlayState gamePlayState;
public PushGame() : base()
{
gamePlayState = new PlayState(this);
}
protected override State GamePlayState
{
get { return gamePlayState; }
}
}
public abstract class ManiaGame
{
protected abstract State GamePlayState { get; }
}
public class State
{
public State(ManiaGame mg) { }
}
public class PlayState : State
{
public PlayState(ManiaGame mg) : base(mg) { }
}