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

Managed class types as type of type parameter T (Error C2670)

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

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 种方法来使该功能起作用,所以我无法告诉您为什么我按原样实现它:-/

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

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,
    // ...
};

此外,还有一位家长 class 持有 ObservableCollection 的狗、猫等:

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

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

编译器抛出以下错误:

error C2670: 'System::Collections::ObjectModel::Collection::Add' : the function template cannot convert parameter 1 from type 'CDog ^'

你能告诉我我做错了什么吗?

!!!解决方案 !!!

基于 ,我最终将构造函数参数移动到一个名为 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);
    }
};

如果我删除与错误无关的内容,这就是我们得到的:

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

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

  • 您可以 return 列表 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() 约束,这意味着 class 有一个零参数构造函数,你可以只使用类型 T 来调用它.
  • 将您当前拥有的构造函数参数移动到 CAnimal 上定义的方法中。这样你就可以在任何 T.
  • 上调用它
  • 我删除了枚举参数。你不需要它;您已经通过通用指定了您想要的动物。
    • 无论您如何实施,我都建议您进行此更改。否则,你将不得不考虑像 GetItems<CDog^>(AnimalType::Cat, 3) 这样的事情应该做什么。