确定泛型类型实例的泛型参数

如果你有泛型类型的实例但由于某种原因不知道特定类型,则可能需要确定用于创建此实例的泛型参数。

假设某人创建了 List<T> 的实例,并将其传递给方法:

var myList = new List<int>();
ShowGenericArguments(myList);

ShowGenericArguments 有这个签名:

public void ShowGenericArguments(object o)

所以在编译时你不知道使用了什么泛型参数来创建 oReflection 提供了许多检查泛型类型的方法。首先,我们可以确定 o 的类型是否是泛型类型:

public void ShowGenericArguments(object o)
{
    if (o == null) return;

    Type t = o.GetType();
    if (!t.IsGenericType) return;
    ...

如果类型是泛型类型,则 Type.IsGenericType 返回 true,如果不是,则返回 false

但这不是我们想知道的全部。List<> 本身也是一种通用类型。但我们只想检查特定构造泛型类型的实例。构造的泛型类型是例如具有特定类型 List<int> 参数用于其所有的通用参数

Type 类提供了另外两个属性 IsConstructedGenericTypeIsGenericTypeDefinition ,以区分这些构造的泛型类型和泛型类型定义:

typeof(List<>).IsGenericType // true
typeof(List<>).IsGenericTypeDefinition // true
typeof(List<>).IsConstructedGenericType// false

typeof(List<int>).IsGenericType // true
typeof(List<int>).IsGenericTypeDefinition // false
typeof(List<int>).IsConstructedGenericType// true

要枚举实例的泛型参数,我们可以使用 GetGenericArguments() 方法返回包含泛型类型参数的 Type 数组:

public void ShowGenericArguments(object o)
{
    if (o == null) return;   
    Type t = o.GetType();
    if (!t.IsConstructedGenericType) return;

    foreach(Type genericTypeArgument in t.GetGenericArguments())
        Console.WriteLine(genericTypeArgument.Name);
}

所以上面的调用(ShowGenericArguments(myList))会产生这样的输出:

Int32