2009-06-12 6 views
3

J'ai écrit cet exemple pour aider à expliquer. Comme vous pouvez le voir, j'ai une hiérarchie d'objets. Je voudrais modifier la fonction GetFeatures() pour retourner uniquement les fonctionnalités ajoutées par le constructeur du type d'objet I instancié. Par exemple, BasicModel.GetFeatures (new LuxuryModel()) ne doit renvoyer que les fonctionnalités "Leather Seats" et "Sunroof". Cela ne me dérange pas d'utiliser la réflexion si je le dois.Comment filtrer une collection d'objets dans une classe de base en fonction du type de la sous-classe créée?

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 

Répondre

1

Si vous voulez garder votre hiérarchie/propriétés actuelles, il suffit de créer une instance de la classe de base et soustraire les fonctionnalités de la classe de base des caractéristiques de la classe dérivée. Vous pouvez également envisager de modifier légèrement la hiérarchie de votre classe pour vous faciliter la tâche. Par exemple, vous pouvez diviser la propriété Features en deux propriétés, par exemple ModelFeatures et AllFeatures. ModelFeatures est spécifique au modèle actuel ("Leather Seats" et "Sunroof" pour LuxuryModel, etc.) AllFeatures renvoie l'union de MyBase.AllFeatures et ModelFeatures. Cela rend l'accès aux propriétés du modèle actuel un accès trivial à la propriété.

P.S. S'il vous plaît pardonner mes erreurs VB, C# est ma langue préférée.

1

Je ne suis pas réel familier avec la syntaxe VB.NET, alors voici la syntaxe C# qui devrait fonctionner:

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

En VB cela ne filtre rien. Toutes les fonctionnalités sont toujours retournées. – adam0101

+1

Peu importe que ce soit fait en VB ou en C#. Si vous utilisez une clause Where comme cela, et les types sont en effet différents (notez que GetType ne compare pas les types de base des deux, seulement le type exact de chaque instance), alors vous devriez obtenir une liste filtrée. Si cela ne fonctionne pas, alors la seule option est que chaque caractéristique du modèle donné soit pour le modèle que vous avez passé. – jrista

1

(en fonction de votre code exemple ci-dessus)

Pour être honnête, je ne suis pas pense que cela appartient à votre Car Heirachy, il me semble que vous voulez obtenir des données statiques et utiliser votre classe de base comme le conteneur pour cela avec vos types decendent comme une clé. Comme vous pouvez le voir, cela conduit à un codage maladroit ou trop complexe pour quelque chose de simple.

Je serais beaucoup plus enclin à mettre vos données statiques où elles appartiennent, (dans ce cas) avec la classe d'entité elle-même. Je ne suis pas un gars VB donc cet extrait de code en C#.

Ainsi, dans la classe d'entités lui-même, ont une propriété statique (ou méthode)

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

et répéter pour vos autres modèles. Alors maintenant vous avez un conteneur pour vos données statiques qui a du sens, la classe elle-même.

1

Puisqu'il n'y a aucun moyen de distinguer une caractéristique d'une autre, vous devez être en mesure de demander à un modèle quelles fonctionnalités il a ajouté. Plutôt que d'ajouter des fonctionnalités à la liste dans votre constructeur, vous devriez avoir une méthode qui retourne une liste des caractéristiques de ce modèle particulier ... ajoute

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

Ensuite, GetFeatures pourraient faire le baissés et demander à l'instance est donné pour la liste des fonctionnalités que ce cas particulier ... ajoute

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

Une autre façon de le faire si vous ne voulez pas que ces données soient statiques (voir mon autre réponse), et vous wnat à être extensible à de nouvelles classes, et pour ces classes pour contrôler les ensembles de fonctionnalités.Puis utilisez le polymorphisme (encore C#, car je ne suis pas VB guy)

Dans votre classe de base, créez une méthode virtuelle qui renvoie des entités, dans vos classes décentes, remplacez la propriété, le polymorphisme autorise vos variables comme type basicmodel tant qu'elles sont construit comme le type descendant pour retourner la bonne liste.

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()); 
} 
Questions connexes