嵌套泛型集合:如何实现从项到容器的引用?

时间:2009-05-11 10:33:53

标签: c# generics collections nested

在使用嵌套泛型集合实现设计时,我偶然发现了由C#不变泛型引起的明显限制:

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

这意味着,以下内容不起作用,显然是由于泛型的不变性:

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 个答案:

答案 0 :(得分:2)

引入一个不依赖于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,它引入了co / contra-variant通用接口。

答案 1 :(得分:0)

该语言不允许您从Collection&lt; T&gt;的子类型转换收集&lt; T&gt;

让我解释原因。

想象一下你有一个Collection&lt; subT&gt;并将其投射到Collection&lt; T&gt;。没关系,因为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>