Question

I'm trying to set up an inheritance hierarchy similar to the following:

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

I would like to only store MotorcycleAxle objects in a Motorcycle object's Axles array, and CarAxle objects in a Car object's Axles array. The problem is there is no way to override the array in the subclass to force one or the other. Ideally something like the following would be valid for the Motorcycle class:

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

but the types have to match when overriding. How can I support this architecture? Will I just have to do a lot of run-time type checking and casting wherever the Axles member is accessed? I don't like adding run-time type checks because you start to lose the benefits of strong typing and polymorphism. There have to be at least some run-time checks in this scenario since the WheelAttached and Left/RightWheelAttached properties depend on the type, but I would like to minimize them.

Was it helpful?

Solution

Use more generics

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

OTHER TIPS

2 options spring to mind. 1 is using generics:

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

The second uses shadowing - and this assumes you have properties:

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>

The problem with shadowing is that you have a generic List. Unfortunately, you can't constrain the list to only contain CarAxle. Also, you can't cast a List<Axle> into List<CarAxle> - even though there's an inheritance chain there. You have to cast each object into a new List (though that becomes much easier with LINQ).

I'd go for generics myself.

I asked a similar question and got a better answer, the problem is related to C#'s support for covariance and contravariance. See that discussion for a little more information.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top