托管类类型作为类型参数T的类型(错误C2670)

时间:2015-08-19 15:38:11

标签: .net generics visual-c++ c++-cli generic-collections

我想创建一个返回类型为ObservableCollection<T>^的集合的泛型函数。调用者为类型参数T传递托管类类型。 这是我对泛型函数的尝试之一,在对其他类的解释之后使用:

generic<class T>
    where T:CAnimal, gcnew()
        ObservableCollection<T>^ GetItems(AnimalType animalType, int count)
    {
        ObservableCollection<T>^ animals = gcnew ObservableCollection<T>();
        for (int i = 0; i < count; i++)
        {
            if (animalType == Dog)
            {
                CDog^ dog = gcnew CDog(i, count - i);
                //CAnimal^ dog = gcnew CDog(i, count - i);
                //T dog = gcnew CDog(i, count - i);
                //T^ dog = gcnew CDog(i, count - i);

                animals->Add(dog);
            }
            //else if (animalType == Cat) { ... }
            //...
        }

        return animals;
    }

因为我尝试了近1632种方法来使该功能正常工作,我无法告诉你为什么我按原样实现它: - /

班级CAnimal CDog 的基类(假设还有更多动物)。 AnimalType 是一个枚举,旨在用于上述函数,以确定用于实例化和添加到集合的正确类类型:

ref class CAnimal
{
public:
    CAnimal(){}
    CAnimal(int _age) { age = _age; }
    int age;
};

ref class CDog : CAnimal {
public:
    CDog(){}
    CDog(int _age, int _other)
        :CAnimal(age), other(_other) {}

    int other;
};

enum AnimalType
{
    Dog,
    Cat,
    Fish,
    // ...
};

此外,有一个家长班持有ObservableCollection的狗,猫等等:

ref class CZoo
{
private:
    ObservableCollection<CDog^>^ dogs;

public:
    CZoo()
    {
        dogs = GetItems<CDog^>(AnimalType::Dog, 3);
    }
};

编译器抛出以下错误:

  

错误C2670:'System :: Collections :: ObjectModel :: Collection :: Add':   函数模板无法从类型'CDog ^'

转换参数1

你能告诉我我做错了吗?

!!!解决方案!!!

基于David Yaws' answer我最终将构造函数参数移动到名为Initialize的新函数中,并删除了enum AnimalTypes。最终代码更改为以下内容:

ref class CAnimal
{
internal:
    virtual void Initialize(int _age, int _other)
    {
        age = _age;
        other = _other;
    }

public:
    int age;
    int other;
};

ref class CDog : CAnimal {};
ref class CCat : CAnimal {};

generic<class T>
    where T:CAnimal, gcnew()
        ObservableCollection<T>^ GetItems(int count)
    {
        ObservableCollection<T>^ animals = gcnew ObservableCollection<T>();
        for (int i = 0; i < count; i++)
        {
            T animal = gcnew T();
            animal->Initialize(i, count - i);
            animals->Add(animal);
        }

        return animals;
    }

ref class CZoo
{
private:
    ObservableCollection<CDog^>^ dogs;
    ObservableCollection<CCat^>^ cats;

public:
    CZoo()
    {
        dogs = GetItems<CDog^>(3);
        cats = GetItems<CCat^>(7);
    }
};

1 个答案:

答案 0 :(得分:1)

如果我删除与错误无关的内容,这就是我们所拥有的内容:

generic<class T>
where T:CAnimal, gcnew()
ObservableCollection<T>^ GetItems()
{
    ObservableCollection<T>^ animals = gcnew ObservableCollection<T>();

    animals->Add(gcnew CDog());

    return animals;
}

现在,如果将其作为GetItems<CCat^>()调用,会发生什么?现在,您尝试将CDog放入CCat列表中,但这不起作用。这就是错误消息所说的内容:CDog可能无法转换为T

如果你想这样做,有几种可能的解决方案:

  • 您可以返回CAnimal的列表。 CDog始终有效,可以放入CAnimal
  • 列表
  • 您可以更改初始化T
  • 列表的方式

我推荐后者,并做这样的事情:

generic<class T>
where T:CAnimal, gcnew()
ObservableCollection<T>^ GetItems(int count)
{
    ObservableCollection<T>^ animals = gcnew ObservableCollection<T>();

    for (int i = 0; i < count; i++)
    {
        T animal = gcnew T();
        animal->Initialize(i, count-i);
        animals->Add(animal);
    }

    return animals;
}
  • 因为你有gcnew()约束,这意味着该类有一个零参数构造函数,你可以使用T类型来调用它。
  • 将您当前拥有的构造函数参数移动到CAnimal上定义的方法中。这样您就可以在任何T上调用它。
  • 我删除了枚举参数。你不需要它;你已经通过通用指定了你想要的动物。
    • 无论您如何实施,我都建议您进行此更改。否则,您必须考虑GetItems<CDog^>(AnimalType::Cat, 3)之类的内容。