visual variable una tipos studio que ejemplo declarar declara datos como clases clase atributos asignacion c# unity3d enums const constants

c# - variable - ¿Cómo puedo obtener el número de enumeraciones como una constante?



que es class en c# (5)

A partir del número total de elementos definidos en una enumeración , veo que puedo obtener el número de enumeraciones usando:

Enum.GetNames(typeof(Item.Type)).Length;

¡Funciona genial!

Pero, necesito este número como un número constante, para que pueda usarlo en la función [Range(int, int)] Unity.

private const int constEnumCount = Enum.GetNames(typeof(Item.Type)).Length;

Lo anterior no funciona, porque el recuento de enum no es un número constante, por lo que no puedo asignarlo a una variable constante.

¿Cómo puedo obtener el número de enumeraciones como una constante?


Desafortunadamente, esto no es posible de ninguna manera significativa debido a limitaciones técnicas:

  • [Range(int,int)] es un atributo, y toda la información proporcionada a un atributo tiene que ser un const
  • La única forma verdaderamente a prueba de balas para obtener el número de valores en una enumeración es usar Enum.GetValues(typeof(MyEnum)).Length o Enum.GetNames(typeof(MyEnum)).Length , que son reflejos de tiempo de ejecución.

Sin embargo, hay hacks que pueden funcionar. Por ejemplo, el valor de una enumeración se puede convertir a un número entero. Mientras nadie defina explícitamente los valores de sus enumeraciones, puede usar el último elemento de su enumeración de la siguiente manera:

[Range(0,(int)MyEnum.LastValue)] public void BlahBlahBlah() {}

Sin embargo, sepa que tan pronto como alguien agregue una nueva entrada a la enumeración después de la que esté usando o reordene los elementos en la enumeración, su código se romperá impredeciblemente y no se comportará como usted desea.

Es triste, pero el compilador de C # no es lo suficientemente inteligente como para hacer cálculos simples en el compilador como los compiladores de Java, C y C ++. Así que incluso el ejemplo que di solo funcionaría realmente si el LastValue no se usara para nada más que para marcar el último elemento en la enumeración. Reduce la complejidad del compilador de C #, que también mejora enormemente la velocidad de compilación para su aplicación. Como tal, hay algunas compensaciones que el equipo C # y CLR tomaron para mejorar su experiencia en otros lugares.


No es posible obtener la cantidad de enumeraciones como const . Enum.GetNames utiliza la reflexión para obtener estas cosas, y eso es inherentemente una operación en tiempo de ejecución. Por lo tanto, no se puede conocer en tiempo de compilación, que es un requisito para ser const .


No puede asignar / crear un const en tiempo de ejecución. Eso es lo que estás tratando de hacer. Un const debe evaluarse completamente en tiempo de compilación , no en tiempo de ejecución.

No estoy seguro acerca de la Unidad (y por qué requiere una const ) , pero buscaría usar readonly

private readonly int constEnumCount = Enum.GetNames(typeof(Item.Type)).Length;


Suponiendo que necesita un const porque está tratando de especificar los valores para un Atributo (¿ este ?), Entonces no tiene suerte.

Tus opciones son:

  1. Hardcode el recuento en la declaración de atributo o como un const sí mismo y tenga cuidado de mantener el recuento en sincronización con la definición enum
  2. Utilice PostSharp u otro marco orientado a aspectos para insertar el atributo por usted. Nunca he hecho esto yo solo pero parece posible ( ¿Cómo inyectar un atributo usando un atributo PostSharp? )

Probablemente también puedas arreglártelas para esto con plantillas T4, pero eso se volvería excesivamente kludgy.

Si fuera yo, a menos que esté hablando pero con cientos de enumeraciones diferentes, codificaré la longitud y tal vez agregue un Assert donde lo necesite.

// WARNING - if you add members update impacted Range attributes public enum MyEnum { foo, bar, baz } [Range(0, 3)] class Test { public Test() { int enumCount = Enum.GetNames(typeof(MyEnum)).Length; int rangeMax = GetType().GetCustomAttributes(typeof(Range), false).OfType<Range>().First().Max; Debug.Assert(enumCount == rangeMax); } static void Main(string[] args) { var test = new Test(); } }


En C #, un const se define como constante, es decir, el valor (¡no el cálculo que lo produjo!) Está directamente integrado en el conjunto compilado.

Para evitar que haga algo problemático, el compilador no le permite asignar el resultado de un cálculo a una const. Para entender por qué, imagina que fuera posible:

A.dll public enum Foo { A, B } B.dll public const NumberOfFoos = Enum.GetNames(typeof(Foo)).Length; // Compiles to: B.dll public const NumberOfFoos = 2;

Ahora cambia A.dll:

A.dll public enum Foo { A, B, C, D } B.dll public const NumberOfFoos = 2; // Oh no!

Por lo tanto, necesitaría recompilar B.dll para obtener el valor correcto.

Se pone peor: imagine que tenía un ensamblado C.dll, que usa B.NumberOfFoos. El valor 2 se incrustó directamente en C.dll, por lo que también necesitaría ser recompilado, después de B.dll, para obtener el valor correcto. Por lo tanto (pozo de éxito), C # no te permite hacer esa asignación a un const.