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

时间:2022-11-30 14:29:06

While implementing a design using nested generic collections, I stumbled across those limitations apparently caused by C#'s invariant Generics:

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

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

That means, the following will not work, apparently due to the invariance of 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; }
    }
}

(In the actual code, both Inner<> and Outer<> implement ICollection<>.)

(在实际代码中,Inner <>和Outer <>都实现了ICollection <>。)

I need the Inner<> objects to have a reference to its container collection in order to access some of its data.

我需要Inner <>对象来引用它的容器集合,以便访问它的一些数据。

How would you implement these nested collections, preferably using a generic approach as outlined above? How would you set the reference to the container collection in the Inner<> class?

您将如何实现这些嵌套集合,最好使用上面概述的通用方法?如何在Inner <>类中设置对容器集合的引用?

Cheers!

2 个解决方案

#1


Introducing a (possibly abstract) base class which is not dependant on TInner may help you:

引入一个不依赖于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; }
    }
}

Or wait for C# 4.0, which introduces co/contra-variant generic interfaces.

或者等待C#4.0,它引入了co / contra-variant通用接口。

#2


The language can't let you convert from Collection<subtype of T> to Collection<T>

该语言不允许您从Collection 转换为Collection

Let me explain why.

让我解释一下原因。

Imagine you have a Collection<subT> and cast it to Collection<T>. That's ok, since subT inherits from T.

想象一下,你有一个Collection 并将其转换为Collection 。没关系,因为subT继承自T.

When you retrieve an object from collection_of_T, you're assured that it's ok.

当您从collection_of_T中检索对象时,您可以确信它没问题。

Later, add a T object to collection_of_T. Now you have, in collection_of_subT an object which is not a subT. Whoops.

稍后,将一个T对象添加到collection_of_T。现在,您在collection_of_subT中拥有一个不是subT的对象。哎呦。

In order to achieve what you want, you must create a new Collection alltogether.

为了达到你想要的效果,你必须一起创建一个新的Collection。

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

Which probably is not good for you. Do you really need the TInner generic argument in the Outer class? Would it be possible to replace with Inner<TInnerItem> in the rest of the code instead?

哪个可能对你不好。你真的需要外类中的TInner泛型参数吗?是否可以在代码的其余部分替换Inner ?

#1


Introducing a (possibly abstract) base class which is not dependant on TInner may help you:

引入一个不依赖于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; }
    }
}

Or wait for C# 4.0, which introduces co/contra-variant generic interfaces.

或者等待C#4.0,它引入了co / contra-variant通用接口。

#2


The language can't let you convert from Collection<subtype of T> to Collection<T>

该语言不允许您从Collection 转换为Collection

Let me explain why.

让我解释一下原因。

Imagine you have a Collection<subT> and cast it to Collection<T>. That's ok, since subT inherits from T.

想象一下,你有一个Collection 并将其转换为Collection 。没关系,因为subT继承自T.

When you retrieve an object from collection_of_T, you're assured that it's ok.

当您从collection_of_T中检索对象时,您可以确信它没问题。

Later, add a T object to collection_of_T. Now you have, in collection_of_subT an object which is not a subT. Whoops.

稍后,将一个T对象添加到collection_of_T。现在,您在collection_of_subT中拥有一个不是subT的对象。哎呦。

In order to achieve what you want, you must create a new Collection alltogether.

为了达到你想要的效果,你必须一起创建一个新的Collection。

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

Which probably is not good for you. Do you really need the TInner generic argument in the Outer class? Would it be possible to replace with Inner<TInnerItem> in the rest of the code instead?

哪个可能对你不好。你真的需要外类中的TInner泛型参数吗?是否可以在代码的其余部分替换Inner ?