3

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

无法从 'Collection<subtype of T> 转换为 '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<>类中容器集合的引用?

干杯!

4

2 回答 2

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 泛型接口。

于 2009-05-11T13:51:05.250 回答
0

该语言不能让您从 Collection<subtype of T> 转换为 Collection<T>

让我解释一下为什么。

假设您有一个 Collection<subT> 并将其转换为 Collection<T>。没关系,因为 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>在其余代码中替换为?

于 2009-05-11T15:22:18.440 回答