Frage

Ich versuche, eine Vererbungshierarchie ähnlich der folgenden einzurichten:

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

Ich möchte nur MotorcycleAxle-Objekte im Axles-Array eines Motorcycle-Objekts und CarAxle-Objekte im Axles-Array eines Car-Objekts speichern.Das Problem besteht darin, dass es keine Möglichkeit gibt, das Array in der Unterklasse zu überschreiben, um das eine oder andere zu erzwingen.Idealerweise würde für die Motorradklasse etwa Folgendes gelten:

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

Beim Überschreiben müssen die Typen jedoch übereinstimmen.Wie kann ich diese Architektur unterstützen?Muss ich einfach überall dort, wo auf das Axles-Mitglied zugegriffen wird, viele Typprüfungen und Umwandlungen zur Laufzeit durchführen?Ich füge nicht gerne Typprüfungen zur Laufzeit hinzu, weil dadurch die Vorteile der starken Typisierung und des Polymorphismus verloren gehen.In diesem Szenario müssen zumindest einige Laufzeitprüfungen durchgeführt werden, da die Eigenschaften „WheelAttached“ und „Left/RightWheelAttached“ vom Typ abhängen, aber ich möchte sie minimieren.

War es hilfreich?

Lösung

Verwenden Sie mehr Generika

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

Andere Tipps

2 Optionen fallen mir ein.1 verwendet Generika:

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

Bei der zweiten Methode wird Shadowing verwendet – und dies setzt voraus, dass Sie über folgende Eigenschaften verfügen:

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>

Das Problem beim Shadowing besteht darin, dass Sie eine generische Liste haben.Leider können Sie die Liste nicht darauf beschränken, nur CarAxle zu enthalten.Außerdem können Sie eine List<Axle> nicht in List<CarAxle> umwandeln – auch wenn dort eine Vererbungskette vorhanden ist.Sie müssen jedes Objekt in eine neue Liste umwandeln (obwohl dies mit LINQ viel einfacher wird).

Ich selbst würde mich für Generika entscheiden.

Ich fragte a ähnliche Frage und eine bessere Antwort erhalten habe, hängt das Problem mit der Unterstützung von Kovarianz und Kontravarianz durch C# zusammen.Weitere Informationen finden Sie in dieser Diskussion.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top