2009-05-11 3 views
4

Während ein Design mit verschachtelten generischen Sammlungen Implementierung stolperte ich über diese Beschränkungen offenbar von C# 's invariant Generics verursacht:Verschachtelte generische Sammlungen: Wie implementiert man die Referenz von einem Artikel zu einem Container?

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

Das heißt, wird Folgendes nicht, offenbar wegen der Invarianz von Generics arbeiten:

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

(im eigentlichen Code, sowohl Inner<> und Outer<>ICollection<> implementieren.)

muss ich die Inner<> Objekte, die auf ihre Containersammlung verweisen sollen, um auf einige ihrer Daten zuzugreifen.

Wie würden Sie diese verschachtelten Sammlungen implementieren, vorzugsweise mit einem generischen Ansatz wie oben beschrieben? Wie würden Sie den Verweis auf die Containersammlung in der Klasse Inner<> festlegen?

Prost!

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

Oder für C# 4.0 warten, die co/kontravarianten generische Schnittstellen führt:

+0

Ich kann meinen Kopf nicht um Ihre Klassen wickeln. Wenn Sie ihnen deutlichere Namen geben, kann ich vielleicht versuchen zu verstehen, was Sie zu tun versuchen. – DonkeyMaster

Antwort

2

eine (möglicherweise Zusammenfassung) Basisklasse Einführung in die Sie nicht abhängig von TInner ist, kann helfen.

+0

Für mein spezifisches Problem wählte ich am Ende diese Lösung. – amain

0

Die Sprache kann nicht lassen Sie sich von Sammlung < Subtyp von T umwandeln > to Collection <T>

Lassen Sie mich erklären, warum.

Stellen Sie sich vor Sie haben eine Sammlung < Unter T > und werfen Sie es auf Sammlung <T>. Das ist in Ordnung, da subT von T erbt.

Wenn Sie ein Objekt von collection_of_T abrufen, sind Sie sicher, dass es in Ordnung ist.

Fügen Sie später ein T Objekt zu collection_of_T hinzu. Jetzt haben Sie in collection_of_subT ein Objekt, das kein subT ist. Hoppla.

Um das zu erreichen, was Sie wollen, müssen Sie eine neue Kollektion erstellen.

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

Was wahrscheinlich nicht gut für Sie ist. Benötigen Sie wirklich das TInner generische Argument in der Outer Klasse? Wäre es möglich, stattdessen mit Inner<TInnerItem> im Rest des Codes zu ersetzen?

+0

Danke für die Antwort. Ich denke, ich verstehe, warum ich diese Art der Konvertierung in C# nicht machen kann. Hier bin ich grundsätzlich an Lösungen zur Lösung des Referenzproblems interessiert: Machen Sie den inneren generischen Collections Store zu einem Verweis auf die äußere generische Collection. In meinem Code fungieren beide Sammlungen meist selbst als Basisklassen.Ich hätte dann spezifische Implementierungen von Inner <>: DerivedInner: Inneres und verwende das Äußere <> wie: Outer amain