泛型类中的泛型集合

本文关键字:集合 泛型 泛型类 | 更新日期: 2023-09-27 18:07:40

我有一个自定义类(我们称之为MyClass),它看起来像这样:

public class MyClass
{
    private List<MyClass> list;
    private object data;
}

然而,我想摆脱object属性,而是使用泛型类。像这样:

public class MyClass<T>
{
    private List<MyClass<T>> list;
    private T data;
}

然而,我需要这样的行为:

MyClass<Foo> foo = new MyClass<Foo>;
foo.list = new List<MyClass<Bar>>;

所以我需要能够有不同的数据类型的foo实例和列表/数据属性在foo。但是通用示例中的T将是相同的,并且只允许这样:

MyClass<Foo> foo = new MyClass<Foo>;
foo.list = new List<MyClass<Foo>>;

foo中的每一项。List将再次拥有一个可能是不同类型的列表。当我编译MyClass时,我不知道列表/数据属性中会有什么数据类型,也不知道会有多少个级别。我该如何构建这种灵活的结构?

泛型类中的泛型集合

泛型被设计成允许编译器执行类型使用检查,它们还提供了一些漂亮的额外好处。

你所描述的不能用泛型实现,如果每次你用一个可能不同类型的列表更新list,那么泛型不能帮助你。

然而,如果这些类型共享一个公共基类型或共享一个公共接口,那么你可以使用它作为列表的T,这将允许你使用它们。

如果MyClass的每个实例只允许MyClass<?>的一种类型的List,那么你可以这样修改MyClass:

public class MyClass<T, TList>
{
    private List<MyClass<T, TList>> list;
    private T data;
}

仅用一个类是无法实现这个目标的。您必须为每个带子的级别构建一个泛型基类,为没有子的最低级别构建一个基类,并为每个层次结构级别构建一个派生类。

基类看起来像这样:

public class MyClass<TData>
{
    public TData Data { get; set; }
}
public class MyClass<TData, TDataChildren, TChildren> : MyClass<TData>
    where TChildren : MyClass<TDataChildren>
{
    public List<TChildren> List { get; set; }
}

每个级别的派生类看起来像这样:

public class Level0 : MyClass<Foo, Bar, Level1> { }
public class Level1 : MyClass<Bar, Fubar, Level2> { }
public class Level2 : MyClass<Fubar> { }

用法:

var root = new Level0();
root.Data = new Foo();
root.List = new List<Level1>
{
    new Level1()
    {
        Data = new Bar(),
        List = new List<Level2>
        {
            new Level2()
            {
                Data = new Fubar()
            }
        }
    }
};

在MyClass中添加第二个类型。

public class MyClass<T, G>
{
    private List<MyClass<G, T>> list;
    private T data;
}

这是假设你不关心列表中嵌套列表的类型。

但是您能详细说明一下您的代码的实用性吗?因为仅用抽象数据很难判断。

我正试图在c++中实现一个非常类似的事情,现在我遇到了同样的问题。模板的问题在于它们是强类型的,MyClass<foo>被视为与MyClass<bar>完全不同且不相关的类型。

我现在玩的是创建一个抽象类,上面有纯虚拟方法,如GetInt, GetDouble, GetBool, GetString。然后,我想有一个模板化的Add,它将实例化适当的具体类并将其添加到我的向量。我不确定它是否会工作,但它是沿着这些行:

class Data
{
public:
    template<typename T> Add(const std::string& key, const T& val)
    {
         Data* pData = NULL;
         //test the type using std::numeric_limits to figure out which concrete
         //type to use.
         m_mapValues[key] = pData;
    }
protected:
    virtual int GetInt() const = 0;
    virtual unsigned int GetUINT() const = 0;
    virtual std::string GetString() const = 0;
    //blah blah more types that you want to handle
private:
    std::map<std::string,Data*> m_mapValues;
};
class UINTData : public Data
{
    //implement pure virtual methods.
}

这显然是不完整的,但我希望它能给你一些想法。