通过generics类中的嵌套枚举的reflection获取枚举值

我需要通过reflection来打印出某些types的枚举值和相应的parsing值。 这在大多数情况下工作正常。 但是,如果枚举在genericstypes中声明, Enum.GetValues将引发以下exception:

 [System.NotSupportedException: Cannot create arrays of open type. ] at System.Array.InternalCreate(Void* elementType, Int32 rank, Int32* pLengths, Int32* pLowerBounds) at System.Array.CreateInstance(Type elementType, Int32 length) at System.Array.UnsafeCreateInstance(Type elementType, Int32 length) at System.RuntimeType.GetEnumValues() 

完整的复制代码:

 using System; public class Program { public static void Main() { var enumType= typeof(Foo<>.Bar); var underlyingType = Enum.GetUnderlyingType(enumType); Console.WriteLine(enumType.IsEnum); foreach(var value in Enum.GetValues(enumType)) { Console.WriteLine("{0} = {1}", value, Convert.ChangeType(value, underlyingType)); } } } public class Foo<T> { public enum Bar { A = 1, B = 2 } } 

或者在这里testing

这是所需的行为,我如何工作?

构build一个types将是一个工作环境,但对我来说是不可接受的,因为它会变得太复杂。

build设一个types将是一个解决方法,但我不能接受,因为它会变得太复杂。

这是获得正常行为的价值的唯一途径。

你可以在开放types的领域,奇怪的是,你可以通过枚举的方式获得值。 您应该尽量避免使用这些值,但可以将它们转换为其基础types。

 public static void Main() { var enumType = typeof(Foo<>.Bar); var underlyingType = Enum.GetUnderlyingType(enumType); foreach(var field in enumType.GetFields(BindingFlags.Public | BindingFlags.Static)) { var value = field.GetValue(null); var underlyingValue = Convert.ChangeType(value, underlyingType); Console.WriteLine($"{field.Name} = {underlyingValue}"); } } 

但是, 更好的解决scheme是使用field.GetRawConstantValue()

 public static void Main() { var enumType = typeof(Foo<>.Bar); foreach(var field in enumType.GetFields(BindingFlags.Public | BindingFlags.Static)) { Console.WriteLine($"{field.Name} = {field.GetRawConstantValue()}"); } } 

这样,如果CLR是固定的,以防止这样奇怪的价值观产生,你的代码不会中断。

这是预期的行为。 打开的genericstypes不能在运行时存在,因此也不能存在于其中。 你可以做到这一点的唯一方法是首先closures任何types的父types,然后使用它来反映枚举:

  var enumType = typeof(Foo<object>.Bar); 

Foo就是所谓的开放types(一种没有完全定义的types,因为它有一个通用的types)并且不允许开放types的数组,你可以通过做

 Array.CreateInstance(typeof(Foo<>), 2) 

由于Enum的GetValues依赖于创build一个数组,所以失败了。 你可以做的

 var enumType = typeof(Foo<object>.Bar); 

(“对象”是一个虚拟的types,所以你不会使用一个开放的types)或者做什么Jon Skeetbuild议。