我正在学习Asp.Net MVC 课程并了解到,对于一个有资格作为控制器操作的方法,
- 它不能有“开放的泛型”
我对泛型有所了解并在一定程度上使用它们,但是:
- 什么是 .Net 中的开放泛型类型。
- 有没有封闭的泛型类型这样的东西?
- 开放泛型类型是一个不经常使用的术语。什么是使用/混淆它?
我正在学习Asp.Net MVC 课程并了解到,对于一个有资格作为控制器操作的方法,
我对泛型有所了解并在一定程度上使用它们,但是:
C# 语言将开放类型定义为类型参数或使用未知类型参数定义的泛型类型:
所有类型都可以分为开放型或封闭型。开放类型是涉及类型参数的类型。进一步来说:
- 类型参数定义开放类型。
- 数组类型是开放类型当且仅当其元素类型是开放类型。
- 当且仅当其一个或多个类型参数是开放类型时,构造类型才是开放类型。当且仅当其一个或多个类型参数或其包含类型的类型参数是开放类型时,构造的嵌套类型才是开放类型。
封闭类型是不是开放类型的类型。
因此T
, List<T>
, and Dictionary<string,T>
, andDictionary<T,U>
都是开放类型(T
andU
是类型参数),而List<int>
andDictionary<string,int>
是封闭类型。
有一个相关的概念:未绑定的泛型类型是具有未指定类型参数的泛型类型。未绑定类型不能在表达式中使用typeof()
,您不能实例化它或调用它的方法。例如,List<>
andDictionary<,>
是未绑定的类型。
澄清开放类型和未绑定类型之间的细微区别:
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>
. 在运行时很明显 type 参数是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,>
or 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 时(例如,通过书写PicnicBlanket<Food> p = new PicnicBlanket<Food>()
),我们现在将其称为closed。
只需添加:
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>
将是一个封闭构造的泛型类型。