在.NET 中“开放泛型类型”到底是什么?

我通过 网络 MVC 课程了解到对于一个控制器的操作来说,

  • 它不能有一个 “开放式通用类型”

我对泛型有所了解,并在一定程度上使用它们,但是:

  • 什么是 开放式泛型类型
  • 封闭的一般类型这种东西吗?
  • 开放泛型类型 是一个不经常使用的术语?
46240 次浏览

C # 语言将开放类型定义为类型参数或用未知类型参数定义的泛型类型:

所有类型都可以分为开放类型和闭合类型。开放式是一种涉及类型参数的类型。更具体地说:

  • Type 参数定义打开的类型。
  • 当且仅当数组类型的元素类型是开放类型时,数组类型才是开放类型。
  • 当且仅当 建造类型的一个或多个类型参数是 开放式时,建造类型才是开放类型。当且仅当 构造的嵌套式类型的一个或多个类型参数或其包含类型的类型参数是开放类型时,构造的嵌套式类型才是开放类型。

封闭式是非开放类型的类型。

因此,TList<T>Dictionary<string,T>Dictionary<T,U>都是开放类型(TU是类型参数) ,而 List<int>Dictionary<string,int>是封闭类型。

还有一个相关的概念: 未绑定的泛型类型是带有未指定类型参数的泛型类型。未绑定类型不能在 typeof()以外的表达式中使用,也不能实例化它或调用它的方法。例如,List<>Dictionary<,>是未绑定类型。

澄清开放类型和未绑定类型之间的细微差别:

class Program {
static void Main() { Test<int>(); }
static void Test<T>() {
Console.WriteLine(typeof(List<T>)); // Print out the type name
}
}

如果运行这个代码片段,它会打印出来

System.Collections.Generic.List`1[System.Int32]

这是 List<int>的 CLR 名称。很明显,在运行时类型参数是 System.Int32。这使得 List<T>成为 约束开放类型。

在运行时,您可以使用反射通过 Type.MakeGenericType将类型参数绑定到未绑定泛型类型的未指定类型参数:

Type unboundGenericList = typeof(List<>);
Type listOfInt = unboundGenericList.MakeGenericType(typeof(int));
if (listOfInt == typeof(List<int>))
Console.WriteLine("Constructed a List<int> type.");

您可以检查一个类型是否是一个未绑定的泛型类型(泛型类型定义泛型类型定义) ,从中可以使用 Type.IsGenericTypeDefinition财产构造绑定类型:

Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); // True
Console.WriteLine(typeof(Dictionary<int,int>).IsGenericTypeDefinition); // False

若要在运行时从构造类型获取未绑定类型,可以使用 Type.GetGenericTypeDefinition

Type listOfInt = typeof(List<int>);
Type list = listOfInt.GetGenericTypeDefinition(); // == typeof(List<>)

注意,对于泛型类型,可以有完全未绑定的类型定义,也可以有完全绑定的定义。您不能绑定某些类型参数而不绑定其他类型参数。例如,你不能有 Dictionary<int,>Dictionary<,string>

“开放泛型类型”只是一种尚未指定其类型的泛型类型(例如,CargoCrate<T>)。一旦指定了具体的类型(例如 CargoCrate<Widget>) ,它就变成“闭合的”。

例如,假设你有这样的东西:

public class Basket<T> {
T[] basketItems;
}


public class PicnicBlanket<T> {
Basket<T> picnicBasket;   // Open type here. We don't know what T is.
}


// Closed type here: T is Food.
public class ParkPicnicBlanket : PicnicBlanket<Food> {
}

在这里,picnicBasket的类型是打开的: 还没有分配给 T的任何东西。当您使用特定类型(例如,通过编写 PicnicBlanket<Food> p = new PicnicBlanket<Food>())创建具体的 PicnicBlanket 时,我们现在将其称为 关门了

顺便说一句:

Dictionary<string, T>(或者更确切地说 Dictionary<string,>)仍然是一种开放类型。

例如:

void Foo<T>(Dictionary<string,T> dic) { ... }

泛型类型有三种,简而言之,在这个(简化的)声明中:

public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
  • Dictionary<TKey, TValue>无界泛型类型无界泛型类型

  • 在本例中,KeyValuePair<TKey, TValue>开放式构造的泛型类型。它有一些类型参数,但是它们已经在其他地方定义了(在本例中是 Dictionary)。

  • Dictionary<string, int>就是 封闭构造的一般类型