c# - que - Obtenga los valores enum a través de la reflexión de enum anidado en clase genérica
enum c# string (3)
Necesito imprimir los valores enum y sus valores subyacentes correspondientes de ciertos tipos que adquiero a través de la reflexión. Esto funciona bien la mayor parte del tiempo. Sin embargo, si la enumeración se declara dentro de un tipo genérico, Enum.GetValues
arroja la siguiente excepción:
[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()
Código completo para la reproducción:
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
}
}
O prueba here
¿Es este comportamiento deseado y cómo trabajo alrededor?
La construcción de un tipo sería un workarround pero inaceptable para mí, ya que sería demasiado complicado.
Un tipo de construcción sería una solución, pero inaceptable para mí, ya que sería demasiado complicado.
Esa es la única forma de obtener valores que se comportarán normalmente.
Puede acceder a los campos de tipo abierto, y lo extraño es que puede obtener valores de esa manera para las enumeraciones. Debería intentar evitar el uso de esos valores, pero puede convertirlos a su tipo subyacente.
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}");
}
}
Sin embargo, una mejor solución es usar 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()}");
}
}
De esta forma, si se corrige CLR para evitar que se produzcan valores tan extraños, su código no se romperá.
Este es el comportamiento esperado. Los tipos genéricos abiertos no pueden existir en tiempo de ejecución, por lo que tampoco puede existir nada que viva dentro de ellos. La única forma en que puede hacer esto es primero cerrando el tipo principal con cualquier tipo, y luego usándolo para reflejar la enumeración:
var enumType = typeof(Foo<object>.Bar);
Foo es lo que se llama un tipo abierto (tipo A que no está completamente definido porque tiene un genérico) y una matriz de tipo abierto no está permitida, puedes simularlo haciendo
Array.CreateInstance(typeof(Foo<>), 2)
Y dado que GetValues of Enum depende de la creación de una matriz, falla. En cambio, podrías hacer
var enumType = typeof(Foo<object>.Bar);
("objeto" es un tipo ficticio para que no trabaje con un tipo abierto) O haga lo que Jon Skeet sugirió.