为什么非泛型派生类型必须指定泛型基类的类型参数 C#

3
在Andrew Tolson的《Pro C#》一书中,作者指出当非泛型类继承泛型基类时,派生类必须指定类型参数。
// Assume you have created a custom
// generic list class.
public class MyList<T>
{
  private List<T> listOfData = new List<T>();
}
// Non-generic classes must specify the type
// parameter when deriving from a
// generic base class.
public class MyStringList : MyList<string>
{}

我不理解的是为什么这是必需的?

如果在派生类中没有明确指定类型参数,编译器怎么能猜出“T”的类型呢? - Leri
您有什么替代方案建议吗? - AakashM
5个回答

7
否则,它就不是一个可用的类型,因为CLR仍然不知道要使用哪种类型来替代“T”。
“List”是一个开放类型,因为“T”尚未被替换为可实例化的类型。你不能创建开放类型的实例。只有在类型变为“闭合”时(即所有类型参数(包括封闭类型和基础类型)都已被替换为可实例化的类型),才能创建该类型的实例。
如果你能声明“class MyTList : MyList { }”,那么你永远无法指定“T”的类型,因为“MyTList”不再包含该类型参数,因此你永远无法实例化“MyTList”。这将不是一个非常有用的类。

5

如果您不指定类型,则唯一的其他选项是使派生类也成为通用类。

public class MyDerivedList<T> : MyList<T>
{
}

4

非泛型类没有类型参数,而泛型类具有一个或多个类型参数。

如果您从一个泛型类继承一个类,而不指定类型参数,则仍然拥有一个泛型类,即

public class MyList<T> : List<T> {} //MyList is still generic

但是
public class MyList : List<T> {} //invalid declaration, what is T ?

所以
public class MyStringList : List<string> {} //specified with string

或者,更加一般化
public class MyArrayList : List<object> {} //specified with object

这里有更详细的解释,因为我喜欢使用术语 "arity"。

在CLR中,类可以具有零个或多个arity,这意味着它们可以指定零个或多个类型参数。但是,CLR不能实例化具有非零arity的类,因此为了做任何有用的事情,必须将类的arity降低到零。

这意味着,虽然我们可以部分地指定类,例如:

public class IntKeyDictionary<TValue> : Dictionary<int, TValue>

减少参数数量,甚至声明类等操作
public class ListAndAHalf<TOne, TTwo> : List<TOne>

增加元数的时候,故事必须以元数为0的类结束,例如List<string>Dictionary<int, double>等...


2
如果不是这样呢?您的 MyStringList 将是通用的(因为没有硬编码类型 T),但它并不是定义上的通用类,因为您构建了一个非通用类。

2

换个角度思考。如果您没有为基本类型指定类型参数,那么MyList<T>应该使用什么类型呢?它仍然是未定义的。

您可以创建一个从另一个泛型类型继承的泛型类型,然后您就不必指定超类型的类型参数;您的客户端可以这样做。


你仍需要指定基类的类型参数,但可以使用自己的类型参数来指定。 - Ben Voigt

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