区分基于非泛型值类型的泛型类型和.NET中的其他泛型类型< 4.5

时间:2013-01-23 10:01:21

标签: .net .net-4.0

对于使用反射创建控件的脚本,我需要区分

  1. 标准值类型,例如Int32
  2. 基于上述类型的通用可空类型,例如Int32?
  3. 其他通用类型,例如List<string>
  4. 在.NET 4.5中,我可以使用

    myType.IsConstructedGenericType
    

    结合使用
    myType.IsValueType
    

    并获取

    1. 假/真
    2. 真/真
    3. 真/假
    4. 但是, IsConstructedGenericType 在早期的.NET版本中不可用。我怎样才能在.NET 4.0中实现这一目标?

2 个答案:

答案 0 :(得分:4)

您可以替换.IsGenericType && !.ContainsGenericParameters

问题是,这不会检测任何泛型类型参数本身是否为开放泛型类型(例如,在typeof(List<List<>>)中),因此您需要使用{{3}递归执行此操作}。

这个示例代码应该可以工作,虽然我没有测试它并且不做任何保证:

public static class TypeExtensions {
    public static bool IsConstructedGenericType(this Type t)
    {
        if (!t.IsGenericType || t.ContainsGenericParameters)
        {
             return false;
        }

        if (!t.GetGenericArguments().All(
             a => !a.IsGenericType || a.IsConstructedGenericType()))
        {
            return false;
        }

        return true;
    }
}

GetGenericArguments的文档提供了有关此事的非常有用的信息。

答案 1 :(得分:1)

IsGenericType将根据您提供的示例执行您想要的操作:

using System;
using System.Collections.Generic;
using System.Reflection;

public class Test
{
    static void Main()
    {
        ShowType(typeof(int));
        ShowType(typeof(int?));
        ShowType(typeof(List<string>));
    }

    static void ShowType(Type type)
    {
        Console.WriteLine("{0} / {1}", type.IsGenericType, type.IsValueType);
    }
}

不同之处在于使用IsConstructedGenericType会为typeof(List<>)返回false,而IsGenericType将返回true。您可以使用Type.ContainsGenericParameters在.NET 2 +中区分它们......虽然在病态情况下即使这样也不足

class Foo<T> : Dictionary<T, string> {}

考虑typeof(Foo<>).BaseType

  • IsConstructedGenericType:True(它包含一个指定的类型参数)
  • IsGenericType:是的
  • ContainsGenericParameters:True(它仍然包含一个未分配的类型参数)

希望这对您来说不是问题。