Qual é a melhor maneira para herdar uma matriz que precisa para armazenar subclasse específica de dados?
-
09-06-2019 - |
Pergunta
Eu estou tentando configurar uma hierarquia de herança semelhante à seguinte:
abstract class Vehicle
{
public string Name;
public List<Axle> Axles;
}
class Motorcycle : Vehicle
{
}
class Car : Vehicle
{
}
abstract class Axle
{
public int Length;
public void Turn(int numTurns) { ... }
}
class MotorcycleAxle : Axle
{
public bool WheelAttached;
}
class CarAxle : Axle
{
public bool LeftWheelAttached;
public bool RightWheelAttached;
}
Eu gostaria de armazenar apenas MotorcycleAxle objetos em uma Motocicleta objeto de Eixos da matriz, e CarAxle objetos em um Carro do objeto Eixos da matriz.O problema é que não existe nenhuma maneira de substituir a matriz na subclasse para forçar um ou outro.Idealmente algo como o seguinte seria válido para a Motocicleta classe:
class Motorcycle : Vehicle
{
public override List<MotorcycleAxle> Axles;
}
mas os tipos de jogo, quando o substituir.Como posso apoiar esta arquitetura?Eu vou ter que fazer um monte de tipo de tempo de execução e verificação de fundição onde os Eixos membro é acessado?Eu não gosto de adição de tipo de tempo de execução verifica porque você começa a perder os benefícios de escrever forte e polimorfismo.Há que ter pelo menos algumas verificações em tempo de execução neste cenário desde o WheelAttached e Esquerda/RightWheelAttached propriedades dependem do tipo, mas eu gostaria de minimizá-los.
Solução
Usar mais genéricos
abstract class Vehicle<T> where T : Axle
{
public string Name;
public List<T> Axles;
}
class Motorcycle : Vehicle<MotorcycleAxle>
{
}
class Car : Vehicle<CarAxle>
{
}
abstract class Axle
{
public int Length;
public void Turn(int numTurns) { ... }
}
class MotorcycleAxle : Axle
{
public bool WheelAttached;
}
class CarAxle : Axle
{
public bool LeftWheelAttached;
public bool RightWheelAttached;
}
Outras dicas
2 opções de primavera para a mente.1 é o uso genéricos:
abstract class Vehicle<TAxle> where TAxle : Axle {
public List<TAxle> Axles;
}
O segundo utiliza o sombreamento - e isso pressupõe ter propriedades:
abstract class Vehicle {
public IList<Axle> Axles { get; set; }
}
class Motorcyle : Vehicle {
public new IList<MotorcycleAxle> Axles { get; set; }
}
class Car : Vehicle {
public new IList<CarAxle> Axles { get; set; }
}
void Main() {
Vehicle v = new Car();
// v.Axles is IList<Axle>
Car c = (Car) v;
// c.Axles is IList<CarAxle>
// ((Vehicle)c).Axles is IList<Axle>
O problema com o sombreamento é que você tem uma Lista genérica.Infelizmente, você não pode se restringir a lista para conter apenas o CarAxle.Além disso, você não pode conjurar uma Lista<Axle> na Lista<CarAxle> - mesmo que há uma cadeia de heranças lá.Você tem que associar cada objeto em uma nova Lista (apesar de que fica muito mais fácil com o LINQ).
Gostaria de ir para os genéricos mim.
Perguntei a um semelhante pergunta e tem uma resposta melhor, o problema está relacionado a C#'s suporte para a covariância e contravariância.Veja-se que a discussão um pouco mais de informações.