2011-03-23 2 views
1

J'ai lu un certain nombre d'autres questions connexes, mais je n'arrive toujours pas à comprendre comment faire ce que nous devons faire. L'utilisation de génériques n'est pas un must, mais semble être le seul moyen d'obtenir ce dont nous avons besoin. Nous sommes en .net 3.5 donc nous ne pouvons pas utiliser les nouveaux trucs .net 4.0 que je crois être liés. Supposons que nous avons une classe de base Parent qui a des propriétés et des méthodes. Nous avons également une ParentCollection qui implémente actuellement IEnumerable. Nous avons également ajouté des propriétés et méthodes supplémentaires sur cette classe.Génériques et héritage avec collections

Nous devons maintenant hériter de Parent pour créer un ChildA. Cependant, nous devons également hériter de ParentCollection pour créer ChildACollection. Nous aurions alors des classes homologues pour ChildA en tant que ChildB et ChildBCollection.

Les ChildACollection et ChildBCollection et leurs éléments sont les seules choses qui sont réellement instanciées. Le truc de Parent est abstrait.

Il existe des méthodes sur ParentCollection ainsi que Parent qui pourraient renvoyer des sous-ensembles d'éléments qui répondent aux critères et qui pourraient également avoir été manipulés.

Le problème est que ces méthodes fonctionnent avec des éléments de la collection, nous aimerions que la collection retournée soit du type du descendant. par exemple. Appelez la méthode SomeMethod() qui est définie dans ParentCollection via une instance d'une ChildACollection afin que le retour de sous-ensemble soit de type List au lieu d'une liste.

Existe-t-il un moyen d'obtenir ce type de fonctionnalité?

Exemple Pseudo Code de ce que nous essayons de faire

public class Parent 
{ 
    public string PropA { get; set; } 
    public int PropB { get; set; } 

    public void DoSomething() { } 
} 

public class ParentCollection : IEnumerable<Parent> 
{ 
    protected List<Parent> _list = new List<Parent>(); 

    public IEnumerator<Parent> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public List<Parent> SomeSelectMethod() 
    { 
     List<Parent> list = new List<Parent>(); 

     // DO LOGIC HERE TO DETERMINE WHAT ITEMS WILL BE IN LIST 

     return list; 
    } 

} 

public class ChildA : Parent 
{ 
    public double PropC { get; set; } 

    public void DoSomethingElse() { } 
} 

public class ChildACollection : ParentCollection 
{ 
    public void SomeChildMethod() { } 
} 

public class MyTestClass 
{ 
    public void Main() 
    { 
     ChildACollection myCollection = new ChildACollection(); 

     //HERE IS THE PROBLEM 
     List<ChildA> childList = myCollection.SomeSelectMethod(); 
    } 

} 

Fondamentalement, je veux profiter de inheritence mais pas faire l'utilisateur du ChildACollection ont constamment jeter un coup ref objet retourné dans la liste à un Objet ChildA. Je veux dire que la liste interne aura des objets ChildA réels et pas des objets Parent mais puisque la méthode est dans la classe ParentCollection, elle sait seulement qu'il s'agit d'un objet de classe Parent ou descendante. J'espère que cela a du sens.

Aide?

SUIVI QUESTION: Je dois prendre ce heirarchy 1 niveau plus profond (Grandchild) et ajouter une méthode Ajouter sur parent qui va créer et ajouter le type d'objet approprate à la liste, à savoir si Ajouter est appelé sur une référence ChildCollection, il doit créer et ajouter un type de Child et renvoyer une référence à cet objet nouvellement créé qui est dans la liste. Possilbe?

+0

Liste protégée _list = nouvelle Liste (); vous savez que vous êtes déjà propriétaire de IEnumerable , il s'agit en fait d'une liste, vous n'avez donc pas besoin d'un élément _list pour faire partie de la classe. –

Répondre

4

Vous pouvez utiliser des contraintes de paramètre de type générique:

class ParentCollection<T> where T : Parent { 
     public List<T> SomeSelectMethod() 
     { 
      List<T> list = new List<T>(); 

      // can treat T as Parent here 

      return list; 
     } 
    } 

    class ChildACollection : ParentCollection<ChildA> { 
    } 

    class ChildBCollection : ParentCollection<ChildB> { 
    } 

Vous pouvez également envisager héritant de System.Collections.ObjectModel.Collection de sorte que vous n'avez pas à mettre en œuvre IEnumerable.

Pour le suivi:

Ma compréhension est que vous souhaitez avoir une méthode parameterless Ajouter() sur la collection parent qui crée une instance de type T, ajoute à la collection et le retourne .Une façon de le faire serait d'ajouter une contrainte supplémentaire sur T:

class ParentCollection<T> where T : new(),Parent { 
     public T Add() { 
     var item = new T(); 
     Add(item); 
     return item; 
     } 
    } 
0

Donc, fondamentalement, vous voulez que la personne soit en mesure d'appeler SomeSelectMethod et obtenir soit List, ou Liste?

Vous pouvez le faire avec un argument générique et un certain LINQ.

public List<T> SomeSelectMethod<T>() 
    where T : Parent 
{ 
    return this.Where(x => x.MatchesSomeExpression && x is T).Cast<T>().ToList(); 
} 
0

Vous pouvez faire de ParentCollection une classe générique. Essayez:

public class ParentCollection<T> : IEnumerable<T> where T:Parent

et remplacer tous dans cette classe.

Ensuite, vous pouvez faire class ChildACollection : ParentCollection<ChildA>

0

est ici une solution.

public class ParentCollection<T> : IEnumerable<T> where T : Parent 
{ 
    protected List<T> _list = new List<T>(); 

    public IEnumerator<T> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public virtual List<T> SomeSelectMethod() 
    { 
     List<T> list = new List<T>(); 

     // DO LOGIC HERE TO DETERMINE WHAT ITEMS WILL BE IN LIST 
     return list; 
    } 
} 

public class ChildACollection : ParentCollection<ChildA> 
{ 
    public void SomeChildMethod() 
    { 
    } 
    //You have the method inherited. 
} 
+0

C'est là que je me dirigeais. J'ai ajouté une question complémentaire sur l'ajout d'un troisième niveau d'héritage. – barrettsm

Questions connexes