好吧,当你写一门课时C<T>
,一切都是关于C
,而不是T
。T
只是提供用于表示特殊C<>
类型的类型信息。C<>
有自己的实现,与T
. 当你写:
var c = new C<int>();
变量的行为c
完全按照你在课堂上写的C<>
。无论T
isint
还是string
什么,它的行为都是一样的。
另请注意,编写为 like 的类C<S>
是一种特殊类型,与C<T>
另一种类型不同,因为所有行为都受到它的C
-ness 的限制。我们永远不知道它是如何C<>
编写的以及它将如何表现。所以你描述的方式不是泛型如何发挥作用。如果您有额外的课程,例如
class D<T> : C<T>
{
}
你可以写:
C<A> c = new D<A>();
你看,这又是可能的,因为C
派生自D
. 班级的左边很重要。这又是非法的:
C<A> c = new D<B>();
即使A
派生自B
,因为与of (甚至C
of )A
没有关系,它是一个单独的类。D
B
C
B
这种泛型多态性实际上是毫无意义的,当你认为C<A>
它们是一种完全不同的类型时,C<B>
尽管它们具有共同的行为。用另一个例子来说明,想想这个,一个类可以是多个类型的泛型。假设有
class C<S, T>
{
}
C<IList<A>, A>
和怎么样C<IList<int>, B>
?它们的类型是否具有可比性,因为这两个具有IList
和A
和B
作为泛型类型?C<T>
浇注料C<S, T>
来自? 不,简而言之,这些是不同的类型。
现在如果你不想做任务
C<A> ca = new C<B>();
可能您可以编写自己的隐式转换器。
class C<T>
{
public static implicit operator C<T>(C<B> c)
{
type check, explode or return
}
}
//now you may write:
C<A> ca = new C<B>();
//or even
C<A> ca = new D<B>();
请注意,这并不意味着继承关系,而只是一种转换操作。
如果没有关于协变和逆变的信息(仅适用于接口和委托),则没有关于泛型的信息是不完整的。如果让这种情况发生,请参阅 OR Mapper 关于危险的回答。C# 允许这样做的一种情况是数组。可悲的是,这是一个破碎的设计。这在 C# 中是可能的
object[] o = new string[1];
o[0] = 1; //explosion
我很想详细说明,但我所做的任何事情都会使它变得多余。有关明确信息,请参阅Eric Lippert的出色回答。