Tengo la siguiente enumeración:
public enum AuthenticationMethod
{
FORMS = 1,
WINDOWSAUTHENTICATION = 2,
SINGLESIGNON = 3
}
Sin embargo, el problema es que necesito la palabra "FORMULARIOS" cuando solicito AuthenticationMethod.FORMS y no la identificación 1.
He encontrado la siguiente solución para este problema ( enlace ):
Primero necesito crear un atributo personalizado llamado "StringValue":
public class StringValue : System.Attribute
{
private readonly string _value;
public StringValue(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
}
Entonces puedo agregar este atributo a mi enumerador:
public enum AuthenticationMethod
{
[StringValue("FORMS")]
FORMS = 1,
[StringValue("WINDOWS")]
WINDOWSAUTHENTICATION = 2,
[StringValue("SSO")]
SINGLESIGNON = 3
}
Y, por supuesto, necesito algo para recuperar ese StringValue:
public static class StringEnum
{
public static string GetStringValue(Enum value)
{
string output = null;
Type type = value.GetType();
//Check first in our cached results...
//Look for our 'StringValueAttribute'
//in the field's custom attributes
FieldInfo fi = type.GetField(value.ToString());
StringValue[] attrs =
fi.GetCustomAttributes(typeof(StringValue),
false) as StringValue[];
if (attrs.Length > 0)
{
output = attrs[0].Value;
}
return output;
}
}
Bien, ahora tengo las herramientas para obtener un valor de cadena para un enumerador. Entonces puedo usarlo así:
string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);
Bien, ahora todo esto funciona como un encanto, pero me parece mucho trabajo. Me preguntaba si hay una mejor solución para esto.
También probé algo con un diccionario y propiedades estáticas, pero tampoco fue mejor.
this
en frente deEnum
su método estático. Entonces puedes hacerloAuthenticationMethod.Forms.GetStringValue();
Respuestas:
Prueba el patrón type-safe-enum .
La actualización de conversión de tipo explícito (o implícito) se puede hacer mediante
Agregar campo estático con mapeo
llenar este mapeo en el constructor de instancias
y agregar operador de conversión de tipo definido por el usuario
fuente
Utilizar el método
como en (Suponga que
Shipper
es una enumeración definida)También hay muchos otros métodos estáticos en la clase Enum que vale la pena investigar ...
fuente
Puede hacer referencia al nombre en lugar del valor utilizando ToString ()
La documentación está aquí:
http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx
... y si nombra sus enumeraciones en Pascal Case (como lo hago yo, como ThisIsMyEnumValue = 1, etc.), podría usar una expresión regular muy simple para imprimir el formulario descriptivo:
que se puede llamar fácilmente desde cualquier cadena:
Salidas:
Eso ahorra correr alrededor de las casas creando atributos personalizados y adjuntándolos a sus enumeraciones o usando tablas de búsqueda para unir un valor de enumeración con una cadena amigable y, lo mejor de todo, es autoadministrable y se puede usar en cualquier cadena Pascal Case que sea infinitamente Más reutilizable. Por supuesto, no le permite tener un nombre descriptivo diferente al de su enumeración que proporciona su solución.
Sin embargo, me gusta su solución original para escenarios más complejos. Podría llevar su solución un paso más allá y convertir su GetStringValue en un método de extensión de su enumeración y luego no necesitaría hacer referencia a él como StringEnum.GetStringValue ...
A continuación, puede acceder fácilmente desde su instancia de enumeración:
fuente
"(?!^)([^A-Z])([A-Z])", "$1 $2"
. Así seHereIsATEST
convierteHere Is ATEST
.Lamentablemente, la reflexión para obtener atributos en las enumeraciones es bastante lenta:
Vea esta pregunta: ¿ Alguien sabe una forma rápida de obtener atributos personalizados en un valor de enumeración?
El
.ToString()
es bastante lento en enumeraciones también.Sin embargo, puede escribir métodos de extensión para enumeraciones:
Esto no es genial, pero será rápido y no requerirá la reflexión de los atributos o el nombre del campo.
Actualización C # 6
Si puede usar C # 6, entonces el nuevo
nameof
operador funciona para las enumeraciones, pornameof(MyEnum.WINDOWSAUTHENTICATION)
lo que se convertirá"WINDOWSAUTHENTICATION"
en tiempo de compilación , por lo que es la forma más rápida de obtener nombres de enumeración.Tenga en cuenta que esto convertirá la enumeración explícita en una constante en línea, por lo que no funciona para las enumeraciones que tiene en una variable. Entonces:
Pero...
fuente
Yo uso un método de extensión:
Ahora decora el
enum
con:Cuando usted llama
AuthenticationMethod.FORMS.ToDescription()
obtendrá"FORMS"
.fuente
using System.ComponentModel;
Además, este método solo funciona si desea que el valor de la cadena sea el mismo que el nombre de Enum. OP quería un valor diferente.AuthenticationMethod.FORMS.ToDescription()
?Solo usa el
ToString()
métodoPara hacer referencia a la cadena
Tomato
, solo usefuente
.ToString()
valor diferente al fácil de usar que necesita.any fruit = any.Tomato;
string tomato = fruit.ToString();
Solución muy simple a esto con .Net 4.0 y superior. No se necesita otro código.
Para obtener la cadena sobre solo use:
o
El valor será "Activo" o "Archivado".
Para ver los diferentes formatos de cadena (la "f" de arriba) al llamar,
Enum.ToString
vea esta página de cadenas de formato de enumeraciónfuente
Uso el atributo Descripción del espacio de nombres System.ComponentModel. Simplemente decore la enumeración y luego use este código para recuperarla:
Como ejemplo:
Este código satisface muy bien las enumeraciones en las que no necesita un "nombre descriptivo" y devolverá solo el .ToString () de la enumeración.
fuente
Realmente me gusta la respuesta de Jakub Šturc, pero su inconveniente es que no se puede usar con una declaración de cambio de mayúsculas y minúsculas. Aquí hay una versión ligeramente modificada de su respuesta que se puede usar con una declaración de cambio:
Entonces obtendrá todos los beneficios de la respuesta de Jakub Šturc, además podemos usarlo con una declaración de cambio como esta:
fuente
public static int nextAvailable { get; private set; }
luego en el constructorthis.Value = nextAvailable++;
=
operador para permitir que el interruptor funcione? Hice esto en VB y ahora puedo usarlo en laselect case
declaración.Utilizo una combinación de varias de las sugerencias anteriores, combinadas con un poco de almacenamiento en caché. Ahora, tuve la idea de un código que encontré en algún lugar de la red, pero no puedo recordar dónde lo obtuve ni lo encontré. Entonces, si alguien encuentra algo similar, por favor comente con la atribución.
De todos modos, el uso implica los convertidores de tipo, por lo que si está vinculado a la interfaz de usuario, 'simplemente funciona'. Puede ampliar con el patrón de Jakub para una búsqueda rápida de código inicializando desde el convertidor de tipos en los métodos estáticos.
El uso base se vería así
El código para el convertidor de tipo de enumeración personalizado es el siguiente:
}
fuente
En su pregunta, nunca dijo que realmente necesita el valor numérico de la enumeración en ninguna parte.
Si no lo hace y solo necesita una enumeración de tipo cadena (que no es un tipo integral, por lo que no puede ser una base de enumeración), aquí hay una manera:
puede usar la misma sintaxis que enum para hacer referencia a ella
Será un poco más lento que con los valores numéricos (comparando cadenas en lugar de números) pero en el lado positivo no está usando la reflexión (lenta) para acceder a la cadena.
fuente
Cómo resolví esto como un método de extensión:
Enum:
Uso (donde o.OrderType es una propiedad con el mismo nombre que la enumeración):
Lo que me da una cadena de "Nueva tarjeta" o "Recargar" en lugar del valor de enumeración real NewCard and Refill.
fuente
Actualización: Visitar esta página, 8 años después, después de no tocar C # durante mucho tiempo, parece que mi respuesta ya no es la mejor solución. Realmente me gusta la solución del convertidor vinculada con las funciones de atributo.
Si está leyendo esto, asegúrese de consultar también otras respuestas.
(pista: están por encima de este)
Como la mayoría de ustedes, me gustó mucho la respuesta seleccionada de Jakub Šturc , pero también odio copiar y pegar el código, y trato de hacerlo lo menos posible.
Así que decidí que quería una clase EnumBase de la que se heredara / incorporase la mayor parte de la funcionalidad, dejándome concentrarme en el contenido en lugar del comportamiento.
El principal problema con este enfoque se basa en el hecho de que, aunque los valores de Enum son instancias de tipo seguro, la interacción es con la implementación estática del tipo de clase Enum. Entonces, con un poco de ayuda de la magia genérica, creo que finalmente obtuve la mezcla correcta. Espero que alguien encuentre esto tan útil como yo.
Comenzaré con el ejemplo de Jakub, pero usando herencia y genéricos:
Y aquí está la clase base:
fuente
Estoy de acuerdo con Keith, pero no puedo votar (todavía).
Utilizo un método estático y una declaración swith para devolver exactamente lo que quiero. En la base de datos, guardo tinyint y mi código solo usa la enumeración real, por lo que las cadenas son para requisitos de IU. Después de numerosas pruebas, esto resultó en el mejor rendimiento y el mayor control sobre la salida.
Sin embargo, según algunas cuentas, esto lleva a una posible pesadilla de mantenimiento y algo de olor a código. Intento vigilar las enumeraciones que son largas y muchas enumeraciones, o las que cambian con frecuencia. De lo contrario, esta ha sido una gran solución para mí.
fuente
Si ha venido aquí para implementar un "Enum" simple pero cuyos valores son cadenas en lugar de ints, esta es la solución más simple:
Implementación:
fuente
static readonly
.Cuando me enfrento a este problema, hay un par de preguntas que primero trato de encontrar las respuestas:
La forma más sencilla de hacerlo es con
Enum.GetValue
(y admite el uso de ida y vueltaEnum.Parse
). A menudo también vale la pena construir unTypeConverter
, como sugiere Steve Mitcham, para soportar el enlace de la interfaz de usuario. (No es necesario construir unaTypeConverter
cuando se usan hojas de propiedades, que es una de las cosas buenas de las hojas de propiedades. Aunque Dios sabe que tienen sus propios problemas).En general, si las respuestas a las preguntas anteriores sugieren que eso no va a funcionar, mi próximo paso es crear y completar una estática
Dictionary<MyEnum, string>
, o posiblemente unaDictionary<Type, Dictionary<int, string>>
. Tiendo a omitir el paso intermedio de decorar-el-código-con-atributos porque lo que viene a continuación es la necesidad de cambiar los valores amigables después del despliegue (a menudo, pero no siempre, debido a la localización).fuente
Quería publicar esto como un comentario a la publicación citada a continuación, pero no pude porque no tengo suficiente representante, así que no desestime el voto. El código contenía un error y quería señalar esto a las personas que intentan usar esta solución:
debiera ser
Brillant!
fuente
Mi variante
El código se ve un poco feo, pero el uso de esta estructura es bastante presentativo.
Además, creo que si se requieren muchas de tales enumeraciones, se podría usar la generación de código (por ejemplo, T4).
fuente
Opción 1:
y entonces
Opcion 2:
fuente
Si piensa en el problema que estamos tratando de resolver, no es una enumeración lo que necesitamos en absoluto. Necesitamos un objeto que permita asociar un cierto número de valores entre sí; en otras palabras, definir una clase.
El patrón de enumeración de tipo seguro de Jakub Šturc es la mejor opción que veo aquí.
Míralo:
fuente
para mí, el enfoque pragmático es clase dentro de clase, muestra:
fuente
Creé una clase base para crear enumeraciones con valores de cadena en .NET. Es solo un archivo C # que puede copiar y pegar en sus proyectos, o instalar a través del paquete NuGet llamado StringEnum . Repo de GitHub
<completitionlist>
. (Funciona tanto en C # como en VB)Instalación:
.Net Standard 1.0
para que se ejecute en.Net Core
> = 1.0,.Net Framework
> = 4.5,Mono
> = 4.6, etc.fuente
Aquí hay otra forma de lograr la tarea de asociar cadenas con enumeraciones:
Este método se llama así:
Puede agrupar enumeraciones relacionadas en su propia estructura. Dado que este método usa el tipo de enumeración, puede usar Intellisense para mostrar la lista de enumeraciones al hacer la
GetString()
llamada.Opcionalmente, puede usar el nuevo operador en la
DATABASE
estructura. No usarlo significa que las cadenasList
no se asignan hasta que se realiza la primeraGetString()
llamada.fuente
Muchas respuestas geniales aquí, pero en mi caso no resolvieron lo que quería de una "enumeración de cadenas", que era:
1,2 y 4 en realidad se pueden resolver con un C # Typedef de una cadena (ya que las cadenas se pueden cambiar en c #)
3 se pueden resolver mediante cadenas constantes estáticas. Entonces, si tiene las mismas necesidades, este es el enfoque más simple:
Esto permite, por ejemplo:
y
Donde CreateType se puede llamar con una cadena o un tipo. Sin embargo, la desventaja es que cualquier cadena es automáticamente una enumeración válida , esto podría modificarse, pero luego requeriría algún tipo de función de inicio ... ¿o posiblemente haría que la conversión explícita sea interna?
Ahora, si un valor int fue importante para usted (tal vez para la velocidad de comparación), podría usar algunas ideas de la fantástica respuesta de Jakub Šturc y hacer algo un poco loco, esta es mi puñalada:
pero por supuesto "Tipos bob = 4;" no tendría sentido a menos que los hayas inicializado primero, lo que podría derrotar el punto ...
Pero en teoría, Tipo A == Tipo B sería más rápido ...
fuente
Si te estoy entendiendo correctamente, simplemente puedes usar .ToString () para recuperar el nombre de la enumeración del valor (suponiendo que ya esté emitido como la enumeración); Si tenía el int desnudo (digamos de una base de datos o algo), primero puede lanzarlo a la enumeración. Los dos métodos a continuación le darán el nombre de enumeración.
Sin embargo, tenga en cuenta que la segunda técnica supone que está usando ints y su índice se basa en 1 (no en 0). La función GetNames también es bastante pesada en comparación, está generando una matriz completa cada vez que se llama. Como puede ver en la primera técnica, .ToString () en realidad se llama implícitamente. Ambos ya se mencionan en las respuestas, por supuesto, solo estoy tratando de aclarar las diferencias entre ellos.
fuente
antiguo post pero ...
La respuesta a esto en realidad puede ser muy simple. Uso Enum.ToString () la función
Hay 6 sobrecargas de esta función, puede usar Enum.Tostring ("F") o Enum.ToString () para devolver el valor de la cadena. No hay necesidad de molestarse con nada más. Aquí hay una demostración en funcionamiento
Tenga en cuenta que esta solución puede no funcionar para todos los compiladores ( esta demostración no funciona como se esperaba ) pero al menos funciona para el compilador más reciente.
fuente
basado en el MSDN: http://msdn.microsoft.com/en-us/library/cc138362.aspx
str serán los nombres de los campos
fuente
Bueno, después de leer todo lo anterior, siento que los muchachos han complicado demasiado el tema de transformar los enumeradores en cadenas. Me gustó la idea de tener atributos sobre campos enumerados, pero creo que los atributos se usan principalmente para metadatos, pero en su caso, creo que todo lo que necesita es algún tipo de localización.
Ahora, si intentamos llamar al método anterior, podemos llamarlo de esta manera
Todo lo que necesita hacer es crear un archivo de recursos que contenga todos los valores del enumerador y las cadenas correspondientes.
Lo que es realmente bueno de eso es que será muy útil si necesita que su aplicación esté localizada, ¡ya que todo lo que necesita hacer es crear otro archivo de recursos con su nuevo idioma! y Voe-la!
fuente
Cuando estoy en una situación así, propongo la solución a continuación.
Y como clase consumidora podrías tener
Y usando un diccionario bidireccional: Basado en esto ( https://stackoverflow.com/a/255638/986160 ) suponiendo que las claves se asociarán con valores únicos en el diccionario y similares a ( https://stackoverflow.com/a / 255630/986160 ) pero un poco más elegante. Este diccionario también es enumerable y puede ir y venir de entrantes a cadenas. Además, no tiene que tener ninguna cadena en su base de código con la excepción de esta clase.
fuente
Para conjuntos de enumeraciones de cadenas más grandes, los ejemplos enumerados pueden volverse cansados. Si desea una lista de códigos de estado, o una lista de otras enumeraciones basadas en cadenas, un sistema de atributos es molesto de usar, y una clase estática con instancias de sí mismo es molesto de configurar. Para mi propia solución, utilizo plantillas T4 para que sea más fácil tener enumeraciones respaldadas por cadenas. El resultado es similar al funcionamiento de la clase HttpMethod.
Puedes usarlo así:
Empiezas con un archivo Enum.tt.
Luego, agrega su archivo StringEnum.ttinclude.
Finalmente, recompilas tu archivo Enum.tt y el resultado se ve así:
fuente