6

我在转换泛型类型时遇到问题。

例如我有课:

public class Dog
{
}

public class Husky : Dog
{

}

public class MyWrapper<T> where T : class
{
}

然后我想做这样的事情,但我不知道怎么做

MyWrapper<Husky> husky = new MyWrapper<Husky>();
List<MyWrapper<Dog>> dogs= new List<MyWrapper<Dog>>();
dogs.Add(husky); // how to cast husky to MyWrapper<Dog>?

编辑:改为Animal<T>MyWrapper<T>所以这将是更充分的例子

4

5 回答 5

8

您可以在 C# 4 或更高版本中使用接口的通用协变。为此,您需要定义一个协变接口(使用out)并MyWrapper实现该接口:

public class Dog 
{
}

public class Husky : Dog
{
}

public class MyWrapper<T> : IMyWrapper<T> where T : class
{
}

public interface IMyWrapper<out T> where T : class
{
}

然后你可以这样做:

var husky = new MyWrapper<Husky>();
var dogs = new List<IMyWrapper<Dog>>();
dogs.Add(husky);
于 2013-01-23T09:11:55.220 回答
7

恐怕你不能——虽然Husky是一个Dog,但Animal<Husky>不是一个Animal<Dog>

有关类似问题,请参阅.NET Casting Generic List 。

于 2013-01-23T09:03:01.010 回答
6

有什么理由不按如下方式安排类继承?我不确定为什么 Animal 需要接受类型参数。

public abstract class Animal
{
}

public class Dog : Animal
{
}

public class Husky : Dog 
{
}
于 2013-01-23T09:03:39.117 回答
5

为此,您需要协方差-向上转换泛型类型-。

但仅支持 C# 协方差:

  • 代表。
  • 接口。

出于这个原因,我只找到了一个解决方案:创建一个标记界面IAnimal<T>

public class Dog
{
}

public class Husky : Dog
{

}

public interface IAnimal<out T>
    where T : class
{
}

public class Animal<T> : IAnimal<T> where T : class
{
}

现在这将起作用:

        List<IAnimal<Dog>> list = new List<IAnimal<Dog>>();
        list.Add(new Animal<Husky>());

在 MSDN 上了解有关协变和逆变的更多信息:

更新

无论如何...通用约束有什么意义T : class?你只知道这T是一个类,但它可能没有公共构造函数,或者它可能是一块石头而不是一条狗,谁知道呢?

或者,这个类层次结构的意义何在?正如其他人在他们的回答中指出的那样,您的层次结构不是非常面向对象的:a Dog IS an animal so Dog DERIVES Animal

只需更改它,您就不再需要使用泛型类型参数。

也许你更喜欢组合而不是继承,但我倾向于决定这个问题的最佳选择:

  • 如果我说专业类型,我可以说“B is A”吗?=>然后我选择继承

  • 如果我谈论专业类型,我可以说“B is part of A” =>然后我选择 composition

实际上,我相信协方差可以解决您的问题,但我觉得这是该语言功能的错误用例。

于 2013-01-23T09:14:59.097 回答
2

not possible Animal<Husky> is not derived from Animal<Dog>.

于 2013-01-23T09:08:25.130 回答