1.继承
就继承关系而言,派生类的未指定参数类型标签必须包含所有父类未指定参数类型,否则报错。原因在于,如果派生类的参数类型标签没有涵盖父类的参数类型标签,则实例化派生类的时候,其父类的未指明具体类型的标签<T>仍然无法指定具体类型,所以产生错误。以下是几种常见的继承情况:
class BaseNode { }
class BaseNodeGeneric<T> { }
// concrete type
class NodeConcrete<T> : BaseNode { }
//closed constructed type
class NodeClosed<T> : BaseNodeGeneric<int> { }
//open constructed type
class NodeOpen<T> : BaseNodeGeneric<T> { }
//No error
class Node1 : BaseNodeGeneric<int> { }
//Generates an error
//class Node2 : BaseNodeGeneric<T> {}
//Generates an error
//class Node3 : T {}
class BaseNodeMultiple<T, U> { }
//No error
class Node4<T> : BaseNodeMultiple<T, int> { }
//No error
class Node5<T, U> : BaseNodeMultiple<T, U> { }
class SampleClass1<T> : IBaseInterface1<T> { } //No error
class SampleClass2<T> : IBaseInterface2<T, string> { } //No error
//Generates an error
//class Node6<T> : BaseNodeMultiple<T, U> {}
class NodeItem<T> where T : System.IComparable<T>, new() { }
class SpecialNodeItem<T> : NodeItem<T> where T : System.IComparable<T>, new() { }
class SuperKeyType<K, V, U>
where U : System.IComparable<U>
where V : new()
{ }
2.包含关系
当一个泛型类的实例作为另一个类的成员时,必须保证外层的泛型类的参数类型标签涵盖内层泛型类的参数类型标签。以下面的代码为例,MyClass类的参数类型标签,必须包括Node<T>泛型类的标签T。除非Node类的标签已经具体化,如指定T为string等,否则必须遵循这条原则。
Class MyClass<T>
{
public Node<T> node = new Node<T>();
}
下面这个例子为错误例子:
//error,实例化MyClass时,Node的<T>标签无法具体化。
Class MyClass
{
public Node<T> node = new Node<T>();
}
但下面这个例子是正确的
//right,Node类已经指明T的具体类型
Class MyClass
{
public Node<string> node;
}
总结:继承关系,子类未知标签必须涵盖父类未知标签,就标签种类而言,前者是后者的超集;包含关系,外层类的未知标签必须涵盖内部类的未知标签,就标签种类而言,前者是后者的超集。