Каков наилучший способ наследовать массив, который должен хранить специфические данные подкласса? - PullRequest
2 голосов
/ 28 августа 2008

Я пытаюсь настроить иерархию наследования, подобную следующей:

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;
}

Я хотел бы хранить только объекты MotorcycleAxle в массиве Axles объекта Motorcycle и объекты CarAxle в массиве Axles объекта Car. Проблема в том, что нет способа переопределить массив в подклассе для принудительного использования одного или другого. В идеале, что-то вроде следующего будет действительным для класса Мотоцикл:

class Motorcycle : Vehicle
{
  public override List<MotorcycleAxle> Axles;
}

но типы должны совпадать при переопределении. Как я могу поддержать эту архитектуру? Должен ли я просто выполнять много проверок и приведение типов во время выполнения везде, где есть доступ к элементу Axles? Мне не нравится добавлять проверки типов во время выполнения, потому что вы начинаете терять преимущества строгой типизации и полиморфизма. В этом сценарии должны быть хотя бы некоторые проверки во время выполнения, поскольку свойства WheelAttached и Left / RightWheelAttached зависят от типа, но я бы хотел их минимизировать.

Ответы [ 3 ]

5 голосов
/ 28 августа 2008

Используйте больше дженериков

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;
}
0 голосов
/ 06 сентября 2008

Я задал аналогичный вопрос и получил лучший ответ, проблема связана с поддержкой C # ковариации и контравариантности. См. Это обсуждение для получения дополнительной информации.

0 голосов
/ 28 августа 2008

2 варианта приходят на ум. 1 использует дженерики:

abstract class Vehicle<TAxle> where TAxle : Axle {
   public List<TAxle> Axles;
}

Второй использует теневое копирование - и это предполагает, что у вас есть свойства:

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>

Проблема с тенями в том, что у вас есть общий список. К сожалению, вы не можете ограничить список только CarAxle. Кроме того, вы не можете преобразовать List в List - даже если там есть цепочка наследования. Вы должны преобразовать каждый объект в новый список (хотя с LINQ это становится намного проще).

Я бы сам пошел на дженерики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...