2009-05-11 6 views
4

Bien que la mise en œuvre d'une conception en utilisant des collections génériques imbriqués, je suis tombé sur ces limitations causées apparemment par Generics invariantes de C#:Collections génériques imbriquées: comment implémenter la référence d'un élément vers un conteneur?

Cannot convert from 'Collection<subtype of T> to 'Collection<T>'

Cela signifie, ce qui suit ne fonctionnera pas, apparemment en raison de l'invariance de Génériques:

class Outer<TInner, TInnerItem> where TInner : Inner<TInnerItem> 
{ 
    public void Add(TInner item) 
    { 
     item.Outer = this; // ERROR: 
      // Cannot implicitly convert from Outer<TInner, TInnerItem> 
      // to Outer<Inner<TInnerItem>, TInnerItem> 
    } 
} 

class Inner<TInnerItem> : ICollection<TInnerItem> 
{ 
    Outer<Inner<TInnerItem>, TInnerItem> _outer; 

    public Outer<Inner<TInnerItem>, TInnerItem> Outer 
    { 
     set { _outer = value; } 
    } 
} 

(Dans le code actuel, à la fois Inner<> et Outer<> mettre en œuvre ICollection<>.)

J'ai besoin Inner<> objets pour avoir une référence à sa collection de conteneurs afin d'accéder à certaines de ses données.

Comment implémenteriez-vous ces collections imbriquées, de préférence en utilisant une approche générique comme indiqué ci-dessus? Comment définiriez-vous la référence à la collection de conteneurs dans la classe Inner<>?

À la votre!

+0

Je ne peux pas envelopper ma tête autour de vos cours. Si vous leur donnez des noms plus distincts, je peux peut-être essayer de comprendre ce que vous essayez de faire. – DonkeyMaster

Répondre

2

L'introduction d'un (peut-être abstraite) classe de base qui ne dépend pas de TInner peut vous aider:

abstract class OuterBase<TInnerItem> 
{ 
} 

class Outer<TInner, TInnerItem> : OuterBase<TInnerItem> where TInner : Inner<TInnerItem> 
{ 
    public void Add(TInner item) 
    { 
     item.Outer = this; // Compiles 
    } 
} 

class Inner<TInnerItem> : ICollection<TInnerItem> 
{ 
    OuterBase<TInnerItem> _outer; 

    public OuterBase<TInnerItem> Outer 
    { 
     set { _outer = value; } 
    } 
} 

Ou attendre C# 4.0, qui introduit des interfaces co/contra-variante générique.

+0

Pour mon problème spécifique, à la fin, j'ai choisi cette solution. – amain

0

La langue ne peut pas vous permettre de convertir de sous-type Collection < de T > Collection <T>

Laissez-moi vous expliquer pourquoi. Imaginez que vous ayez une collection <subT> et que vous la transtypiez dans la collection <T>. C'est bon, puisque subT hérite de T.

Lorsque vous récupérez un objet de collection_of_T, vous êtes assuré que tout va bien. Par la suite, ajoutez un objet T à collection_of_T. Maintenant vous avez, dans collection_of_subT un objet qui n'est pas un subT. Oups.

Afin de réaliser ce que vous voulez, vous devez créer une nouvelle collection tous ensemble.

Collection<T> collection_of_T = new Collection<T>(collection_of_subT); 

Ce qui n'est probablement pas bon pour vous. Avez-vous vraiment besoin de l'argument générique TInner dans la classe Outer? Serait-il possible de remplacer par Inner<TInnerItem> dans le reste du code à la place?

+0

Merci de votre réponse. Je pense que je comprends pourquoi je ne peux pas faire ce type de conversion en C#. Ici, je m'intéresse fondamentalement aux solutions sur la façon de résoudre le problème de référence: Faire du magasin de collection générique interne une référence à la collection générique externe. Dans mon code, les deux collections agissent principalement comme des classes de base elles-mêmes.J'aurais alors des implémentations spécifiques de Inner <>: DerivedInner: Inner et utiliser le <> comme: Outer amain

Questions connexes