Вложенные универсальные коллекции: как реализовать ссылку от элемента к контейнеру? - PullRequest
4 голосов
/ 11 мая 2009

При реализации проекта с использованием вложенных универсальных коллекций я наткнулся на эти ограничения, очевидно вызванные инвариантом C # Generics:

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

Это означает, что следующее не будет работать, по-видимому, из-за неизменности Generics:

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

(В фактическом коде оба Inner<> и Outer<> реализуют ICollection<>.)

Мне нужно, чтобы объекты Inner<> имели ссылку на свою коллекцию контейнеров, чтобы получить доступ к некоторым ее данным.

Как бы вы реализовали эти вложенные коллекции, предпочтительно используя общий подход, как описано выше? Как бы вы указали ссылку на коллекцию контейнеров в классе Inner<>?

Ура!

Ответы [ 2 ]

2 голосов
/ 11 мая 2009

Введение (возможно, абстрактного) базового класса, который не зависит от TInner, может вам помочь:

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

Или дождитесь C # 4.0, который вводит обобщенные / противоречивые универсальные интерфейсы.

0 голосов
/ 11 мая 2009

Язык не может позволить вам конвертировать из Collection <подтип T> в Collection

Позвольте мне объяснить, почему.

Представьте, что у вас есть Коллекция и приведите ее к Коллекции . Это нормально, так как subT наследуется от T.

Когда вы извлекаете объект из collection_of_T, вы уверены, что все в порядке.

Позже, добавьте объект T к collection_of_T. Теперь у вас есть collection_of_subT объект, который не является subT. Упс.

Чтобы достичь того, чего вы хотите, вы должны полностью создать новую коллекцию.

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

Что, вероятно, не хорошо для вас. Вам действительно нужен универсальный аргумент TInner в классе Outer? Можно ли заменить на Inner<TInnerItem> в остальной части кода вместо этого

...