0

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

  1. 标准值类型,如Int32
  2. 基于上述类型的通用可空类型,例如Int32?
  3. 其他通用类型,如List<string>

在 .NET 4.5 中,我可以使用

myType.IsConstructedGenericType

结合

myType.IsValueType

并得到

  1. 假/真
  2. 真/真
  3. 真假

但是,IsConstructedGenericType在早期的 .NET 版本中不可用。如何在 .NET 4.0 中实现这一点?

4

2 回答 2

4

你可以用.IsGenericType && !.ContainsGenericParameters那个代替。

问题是这不会检测任何泛型类型参数本身是否是开放泛型类型(例如 in typeof(List<List<>>)),因此您需要使用GetGenericArguments.

此示例代码应该可以工作,尽管我没有对其进行测试并且不做任何保证:

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;
    }
}

的文档IsGenericType提供了有关此问题的非常有用的信息。

于 2013-01-23T10:04:50.327 回答
1

IsGenericType will do what you want for the examples you've given:

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);
    }
}

The difference is that using IsConstructedGenericType would return false for typeof(List<>) whereas IsGenericType will return true. You can use Type.ContainsGenericParameters to distinguish between them in .NET 2+... although even that's not quite enough, in pathological cases:

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

Consider typeof(Foo<>).BaseType:

  • IsConstructedGenericType: True (it contains one assigned type parameter)
  • IsGenericType: True
  • ContainsGenericParameters: True (it still contains one unassigned type parameter)

Hopefully this won't be an issue for you.

于 2013-01-23T10:06:04.783 回答