Qual è il modo migliore per ereditare un array che deve memorizzare dati specifici della sottoclasse?

StackOverflow https://stackoverflow.com/questions/31088

Domanda

Sto cercando di impostare una gerarchia di ereditarietà simile alla seguente:

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

Vorrei memorizzare solo oggetti MotorcycleAxle nell'array Axles di un oggetto Motorcycle e oggetti CarAxle nell'array Axles di un oggetto Car.Il problema è che non c'è modo di sovrascrivere l'array nella sottoclasse per forzare l'uno o l'altro.Idealmente per la classe Motocicletta sarebbe valido qualcosa come il seguente:

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

ma i tipi devono corrispondere durante l'override.Come posso supportare questa architettura?Dovrò semplicemente eseguire molti controlli e casting del tipo in fase di esecuzione ovunque si acceda al membro Axles?Non mi piace aggiungere controlli del tipo in fase di esecuzione perché inizi a perdere i vantaggi della tipizzazione forte e del polimorfismo.Devono esserci almeno alcuni controlli in fase di esecuzione in questo scenario poiché le proprietà WheelAttached e Left/RightWheelAttached dipendono dal tipo, ma vorrei ridurle al minimo.

È stato utile?

Soluzione

Usa più farmaci generici

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

Altri suggerimenti

Mi vengono in mente 2 opzioni.1 utilizza farmaci generici:

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

Il secondo utilizza lo shadowing e questo presuppone che tu abbia proprietà:

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>

Il problema con lo shadowing è che hai un elenco generico.Sfortunatamente, non puoi limitare l'elenco a contenere solo CarAxle.Inoltre, non puoi eseguire il cast di List<Axle> in List<CarAxle>, anche se lì è presente una catena di ereditarietà.Devi inserire ogni oggetto in un nuovo List (anche se diventa molto più semplice con LINQ).

Io stesso opterei per i generici.

Ho chiesto a domanda simile e ho ottenuto una risposta migliore, il problema è legato al supporto di C# per covarianza e controvarianza.Vedi quella discussione per qualche informazione in più.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top