在C#中转换泛型类

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>,以便它成为更合适的示例。
5个回答

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

generic covariance

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);

7

很抱歉,你不能这样做 - 虽然 Husky 是一种 Dog,但 Animal<Husky> 不是一个 Animal<Dog>

请参考.NET Casting Generic List中的类似问题。


2
通常情况下,泛型会继承它们的泛型类型,就是这样 - 参数的层次结构不会被保留。这也是有道理的,因为可能并不总是可能这样做(具有多个参数)。 - TomTom

6

你为什么不按照以下方式安排类继承呢?我不确定为什么Animal需要接受一个类型参数。

public abstract class Animal
{
}

public class Dog : Animal
{
}

public class Husky : Dog 
{
}

同意,尽管我只能说 - 他做了一个不错的例子,因此它应该保留。如果那是一个真正的类层次结构,正如你所指出的,这是滥用泛型而不是简单的继承。 - TomTom

5

你需要 covariance 来实现 - 将一个泛型类型向上转型/upcasting -。

但是C#的covariance只支持以下两种情况:

  • 委托(Delegates)。
  • 接口(Interfaces)。

因此,我找到了一种解决方案: 创建一个标记接口 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 是一个类,但它可能没有公共构造函数,或者它可能是一块石头而不是一只狗,谁知道呢?

或者,这个类层次结构有什么意义呢?正如其他人在他们的答案中指出的那样,您的层次结构并不是非常面向对象:Dog 是 Animal,所以 Dog 派生自 Animal。

只要改变这一点,您就失去了使用泛型类型参数的需要。

也许您更喜欢组合而不是继承,但我倾向于通过以下问题来决定什么最好:

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

  • 如果我谈论专业类型,我可以说“B是A的一部分”吗? => 然后我选择组合

实际上,我认为协变性解决了您的问题,但我觉得这是该语言特性的错误用例。


可以了,谢谢!在我的项目中有一个类似于class Wrapper<T>的东西,所以它不会被类型为T的类继承。抱歉,我用Animal<T>举的例子不太恰当。但是无论如何感谢您解决了我的问题。 - vanilla161
是的,我也想到了(关于包装器的事情),但我必须回答您实际问题的文本 :) @vanilla161 - Matías Fidemraizer

2

不可能 Animal<Husky> 不是从 Animal<Dog> 派生出来的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接