3 Stimmen

Wie filtert man eine Sammlung von Objekten in einer Basisklasse auf der Grundlage des Typs der erstellten Unterklasse?

Ich habe dieses Beispiel geschrieben, um es zu erklären. Wie Sie sehen können, habe ich eine Objekthierarchie. Ich möchte die Funktion GetFeatures() so ändern, dass sie nur die Merkmale zurückgibt, die durch den Konstruktor des von mir instanziierten Objekttyps hinzugefügt wurden. Zum Beispiel sollte BasicModel.GetFeatures(new LuxuryModel()) nur die Merkmale "Ledersitze" und "Schiebedach" zurückgeben. Wenn es sein muss, verwende ich auch gerne Reflection.

Public Class Feature

    Public Sub New(ByVal model As BasicModel, ByVal description As String)
        _model = model
        _description = description
    End Sub

    Private _model As BasicModel
    Public Property Model() As BasicModel
        Get
            Return _model
        End Get
        Set(ByVal value As BasicModel)
            _model = value
        End Set
    End Property

    Private _description As String
    Public Property Description() As String
        Get
            Return _description
        End Get
        Set(ByVal value As String)
            _description = value
        End Set
    End Property

End Class

Public Class BasicModel
    Public Sub New()
        _features = New List(Of Feature)
    End Sub

    Private _features As List(Of Feature)

    Public ReadOnly Property Features() As List(Of Feature)
        Get
            Return _features
        End Get
    End Property

    Public Shared Function GetFeatures(ByVal model As BasicModel) As List(Of Feature)
        'I know this is wrong, but something like this...'
        Return model.Features.FindAll(Function(f) f.Model.GetType() Is model.GetType())
    End Function
End Class

Public Class SedanModel
    Inherits BasicModel

    Public Sub New()
        MyBase.New()
        Features.Add(New Feature(Me, "Fuzzy Dice"))
        Features.Add(New Feature(Me, "Tree Air Freshener"))
    End Sub
End Class

Public Class LuxuryModel
    Inherits SedanModel

    Public Sub New()
        MyBase.New()
        Features.Add(New Feature(Me, "Leather Seats"))
        Features.Add(New Feature(Me, "Sunroof"))
    End Sub
End Class

1voto

micahtan Punkte 17264

Wenn Sie Ihre aktuelle Hierarchie/Eigenschaften beibehalten wollen, erstellen Sie einfach eine Instanz der Basisklasse und subtrahieren die Features in der Basisklasse von den Features in der abgeleiteten Klasse.

Alternativ können Sie auch Ihre Klassenhierarchie ein wenig ändern, um es sich leichter zu machen.

Sie könnten zum Beispiel die Eigenschaft Features in zwei Eigenschaften aufteilen, zum Beispiel ModelFeatures und AllFeatures.

ModelFeatures ist spezifisch für das aktuelle Modell ("Ledersitze" und "Schiebedach" für LuxuryModel, usw.) AllFeatures gibt die Vereinigung von MyBase.AllFeatures und ModelFeatures zurück. Dies macht den Zugriff auf die Eigenschaften des aktuellen Modells zu einer trivialen Eigenschaft.

P.S. Bitte verzeihen Sie meine VB-Fehler, C# ist meine bevorzugte Sprache.

1voto

jrista Punkte 31522

Ich bin nicht wirklich vertraut mit VB.NET-Syntax, so ist hier C#-Syntax, die funktionieren sollte:

public IList<Function> GetFeatures(BasicModel model)
{
    return model.Features.Where(f => f.Model.GetType() == model.GetType()).ToList();
}

1voto

Tim Jarvis Punkte 17605

(basierend auf Ihrem obigen Beispielcode)

Um ehrlich zu sein, glaube ich nicht, dass dies in Ihre Car Heirachy gehört, es scheint mir, dass Sie auf statische Daten zugreifen wollen und Ihre Basisklasse als Container dafür verwenden, mit Ihren abhängigen Typen als Schlüssel. Wie Sie sehen können, führt dies zu einigen ungeschickt oder übermäßig komplexe Codierung für etwas einfach.

Ich wäre viel eher geneigt, Ihre statischen Daten dort abzulegen, wo sie hingehören, nämlich (in diesem Fall) in der Feature-Klasse selbst. Ich bin nicht ein VB Kerl, so dass dieser Code-Schnipsel in C#.

In der Feature-Klasse selbst müssen Sie also eine statisch Eigenschaft (oder Methode)

public static IEnumerable<Feature> GetLuxuryFeatureSets
{
  get
  {
    yield return new Feature() { Name = "Leather Seats" };
    yield return new Feature() { Name = "Sunroof" };
  }
}

Wiederholen Sie dies für Ihre anderen Modelle. Jetzt haben Sie also einen Container für Ihre statischen Daten, der Sinn macht, nämlich die Klasse selbst.

1voto

JP Alioto Punkte 44283

Da es keine Möglichkeit gibt, ein Merkmal von einem anderen zu unterscheiden, müssen Sie in der Lage sein, ein Modell zu fragen, welche Merkmale es hinzugefügt hat. Anstatt der Liste in Ihrem Konstruktor Features hinzuzufügen, sollten Sie eine Methode haben, die eine Liste von Features zurückgibt, die ein bestimmtes Modell hinzugefügt hat ...

public class LuxuryModel
{
  public LuxuryModel
  {
     Features.Add( GetFeatures() );
  }
  public List<Features> GetFeatures()
  {
     return new List<Features>( /* new up leather and whatever */
  }
}

Dann könnte GetFeatures den Downcast durchführen und die Instanz, die es erhält, nach der Liste der Merkmale fragen, die diese bestimmte Instanz hinzufügt ...

public List<Features> GetFeatures<T>( BasicModel model )
{
   var m = Model as T;
   return m.GetFeatures();
}

1voto

Tim Jarvis Punkte 17605

Ein anderer Weg, dies zu tun, wenn Sie nicht wollen, dass diese Daten statisch sind (siehe meine andere Antwort), und Sie wnat es zu neuen Klassen erweiterbar sein, und für diese Klassen, um die Feature-Sets zu steuern. Dann verwenden Sie Polymorphismus (wieder C#, da ich kein VB-Kenner bin)

In Ihrer Basisklasse erstellen Sie eine virtuelle Methode, die Merkmale zurückgibt, in Ihren dezentralen Klassen überschreiben Sie die Eigenschaft, Polymorphismus erlaubt Ihren Variablen als Typ basicmodel, solange sie als absteigender Typ konstruiert wurden, um die richtige Liste zurückzugeben.

  public class BasicModel
  {
    public virtual IEnumerable<Feature> GetFeatures 
    {
      get
      {
        throw new NotImplementedException();
      }
    }
  }

  public class LuxuryModel :BasicModel
  {
    public override IEnumerable<Feature> GetFeatures
    {
      get
      {
        yield return new Feature() { Name = "Leather Seats" };
        yield return new Feature() { Name = "Sunroof" };
      }
    }
  }

private void button1_Click(object sender, EventArgs e)
{
  StringBuilder sb = new StringBuilder();

  BasicModel bm = new LuxuryModel();

  foreach (Feature f in bm.GetFeatures)
  {
    sb.AppendLine(f.Name);
  }
  MessageBox.Show(sb.ToString());
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X