2010-03-31 15 views
8

que tienen enumeración de esta manera:¿Cuál es la mejor forma de convertir enum a string?

public enum ObectTypes 
{ 
    TypeOne, 
    TypeTwo, 
    TypeThree, 
    ... 
    TypeTwenty 
} 

entonces necesito para convertir esta enumeración de cadena. Ahora estoy haciendo esto de esa manera:

public string ConvertToCustomTypeName(ObjectTypes typeObj) 
{ 
    string result = string.Empty; 
    switch (typeObj) 
    { 
     case ObjectTypes.TypeOne: result = "This is type T123"; break; 
     case ObjectTypes.TypeTwo: result = "Oh man! This is type T234"; break; 
     ... 
     case ObjectTypes.TypeTwenty: result = "This is type last"; break; 
    } 

    return result; 
} 

Im bastante seguro de que no hay mejor manera de no hacer esto, Im en busca de alguna solución de buenas prácticas.

EDIT: No hay un patrón en la cadena de resultados.

Gracias de antemano.

+0

También FWIW no necesita el objeto resultante en absoluto, solo devuelve esas cadenas y también puede deshacerse de las declaraciones de interrupción. –

+0

@Chris Marisic. Sí, tienes razón, pero esa variable solo sirve para una mejor lectura :-) – Dariusz

Respuesta

19

I utilizar el atributo [Description] de System.ComponentModel

Ejemplo:

public enum RoleType 
{ 
    [Description("Allows access to public information")] Guest = 0, 
    [Description("Allows access to the blog")] BlogReader = 4, 
} 

Luego, para leer de él hago

public static string ReadDescription<T>(T enumMember) 
{ 
    var type = typeof (T); 

    var fi = type.GetField(enumMember.ToString()); 
    var attributes = (DescriptionAttribute[]) 
      fi.GetCustomAttributes(typeof (DescriptionAttribute), false); 
    return attributes.Length > 0 ? 
     attributes[0].Description : 
     enumMember.ToString(); 
} 

Entonces uso

ReadDescription(RoleType.Guest);

Nota: esta solución supone una sola aplicación cultura como nada se le preguntó específicamente acerca de múltiples culturas. Si se encuentra en una situación en la que necesita manejar culturas múltiples, yo usaría el DescriptionAttribute o similar para almacenar una clave de un archivo de recursos con reconocimiento cultural. Mientras que podría almacenar el miembro enum directamente en el archivo .resx que crearía el acoplamiento más ajustado posible. No veo ninguna razón por la que desee combinar el funcionamiento interno de su aplicación (los nombres de los miembros enum) con los valores clave que existen para fines de internacionalización.

+3

Esto es terriblemente lento, puede o no ser importante, dependiendo del uso. –

+6

La optimización prematura es el demonio. Si el rendimiento es una consideración seria, puede implementar el almacenamiento en caché y solo necesita leer cada miembro enum una vez. Utilizo esto para rellenar listas desplegables, así que almaceno copias en singleton de mis enumeraciones de pares Código/Valor en mi modelo después de iterar sobre la enumeración una vez. Si estuviera preocupado por el costo de la reflexión, lo almacenaría en caché dentro del método ReadDescription en alguna clase de diccionario o hashtable, etc. –

+0

Esta es una gran técnica para tratar con enumeraciones, aunque sería mucho más limpio si la enumeración tuviera una ' El método GetDescription' o algo así (y si puede poner la descripción * después de * la enumeración). – MusiGenesis

2

Creo que la manera más fácil es tener una función que se correlacione entre el valor enum y el nombre corto preferido y luego crear otra función que genere el mensaje completo.

internal static string MapToName(ObjectTypes value) { 
    switch (value) { 
    case ObjectTypes.TypeOne: return "T123"; 
    case ObjectTypes.TypeTwo: return "T234"; 
    ... 
    } 
} 

public string ConvertToCustomTypeName(ObjectTypes value) { 
    return String.Format("This is type {0}", MapToName(value)); 
} 
+0

Es obvio que quiere convertirla en una cadena arbitraria, no en el nombre del campo enum. –

+0

@Matti, gracias perdí eso. Respuesta actualizada – JaredPar

+0

El prefijo no es constante, el sufijo tampoco es constante, por lo que no puedo predecir el inicio de la cadena. – Dariusz

9

Si necesita una cadena personalizada, la mejor opción sería hacer una Dictionary< ObjectTypes, string>, y simplemente hacer una búsqueda en el diccionario.

Si estás bien con la funcionalidad ToString() por defecto, sólo tiene que utilizar typeObj.ToString();

Para el enfoque de diccionario, que podría hacer:

private static Dictionary<ObjectTypes, string> enumLookup; 

static MyClass() 
{ 
    enumLookup = new Dictionary<ObjectTypes, string>(); 
    enumLookup.Add(ObjectTypes.TypeOne, "This is type T123"); 
    enumLookup.Add(ObjectTypes.TypeTwo, "This is type T234"); 
    // enumLookup.Add... 

} 

Su método se convierte en:

public string ConvertToCustomTypeName(ObjectTypes typeObj) 
{ 
    // Shouldn't need TryGetValue, unless you're expecting people to mess with your enum values... 
    return enumLookup[typeObj]; 
} 
+0

Siento la necesidad de señalar que para las enumeraciones compactas (sin espacios de gran valor), una lista sería mucho más eficiente. –

+0

@Simon: Sí, potencialmente, aunque esto es más flexible, para cualquier tipo de valor en la enumeración, con cualquier valor de enumeración arbitrario ... –

+0

@Simon: aunque eso solo es cierto, también, si los valores enum comienzan en o cerca de 0 ... Comienza a obtener "valores" que no se pueden convertir fácilmente en índices de lista, y el hash será más rápido. –

1

Una vez usé un atributo personalizado en los campos enum que tomaba un parámetro de cadena y luego escribía una función para extraer la cadena cuando se le daba un valor enum.

+0

Huh, no sabía que los miembros enum eran atribuibles :). –

0

Esto requiere refactorización, diría yo.

Replace Type Code With Class

+0

No necesariamente estoy de acuerdo con esto, sería más de matar si realmente es una enumeración que tiene valores de código y de visualización. Con frecuencia utilizo Enums para poblar DropDowns. –

1

Si simplemente desea utilizar el nombre de enumeración (es decir TypeOne) sólo tiene que llamar ToString() en la propia enumeración

typeObj.ToString() 

Si quieres una cadena personalizada en base a la Escriba que tiene varias opciones diferentes. La declaración de cambio que tienes es correcta, pero mantenerla se complicará si tienes una gran cantidad de enumeraciones. O puede configurar un diccionario basado en el tipo de enumeración como la clave y la cadena como el valor.

public enum ObectTypes 
{ 
    One, 
    Two 
} 

Dictionary<ObectTypes, String> myDic = new Dictionary<ObectTypes, string>(); 
myDic.Add(ObectTypes.One, "Something here for One"); 
myDic.Add(ObectTypes.Two, "Something here for Two"); 
1

No puedo creer esto ... ¿por qué nadie ha sugerido un archivo de recursos?

La asignación de valores enum a cadenas dentro del código compilado está muy bien como un truco rápido, pero a largo plazo es una mala práctica y hace que sea difícil refactorizar el código. ¿Qué sucede si agrega (o resta) un valor de la enumeración? Si usa cadenas de un archivo de recursos, todo lo que tiene que hacer es agregar (o eliminar) una entrada.

+1

No creo que muchos programadores de C# usen el archivo de recursos. Parece ser que los codificadores de C++/win32/MFC ven la luz del archivo de recursos. – Justin

+0

@Justin - estoy de acuerdo, no hay suficientes personas que los usen, posiblemente un mal hábito dejado de los viejos tiempos de hacer código VB6, etc. También creo que a medida que más personas sepan separar correctamente la IU de la lógica comercial (es decir, MVVM patrón), entonces las personas comenzarán a usar más los archivos de recursos, especialmente porque los archivos de recursos se pueden utilizar como parte de un enlace estático. – slugster

+0

-1 No estoy de acuerdo en que sea una mala práctica, he usado este método por años sin dolor. El único momento en que no tiene sentido es si la lista tiene cambios dinámicos y con frecuencia, en ese punto las enumeraciones no tienen sentido independientemente de si se usan descripciones o no. –

4

use la forma de Recursos sugerido:

string GetName(Enum e) { 
    return Properties.Resources.ResourcesManager.GetString("_enum_"+e.GetType().ToString().Replace('.','_')); 
} 

El manejo de errores es un poco más ..

1

me gustaría poner estos valores en una base de datos. Las funciones suelen pertenecer a una base de datos por varias razones, entre ellas:

  1. Es posible que sea necesario ejecutar informes con los roles, por lo que es necesario mostrar las descripciones.
  2. Las definiciones de roles se pueden configurar sin implementar código nuevo.
  3. Las funciones se deben aplicar con una restricción de clave.

Si se realiza correctamente, el rendimiento no debería ser un problema para obtener los roles de la base de datos. Además, debido a que una tabla de definición de roles rara vez cambia, es un muy buen candidato para el almacenamiento en caché.

Si tiene que hackear un Enum para que funcione, quizás no debería usar un Enum. Dada la ubicación adecuada, todo debería fluir mucho mejor en el código con poco o ningún hackeo. Los Enum concedidos tienen su lugar; por ejemplo, un estado mutuamente exclusivo y estático.

0

Lo que ya estaba usando no es un mal patrón. Casi todas las demás opciones tienen sus propios problemas. Si estaba utilizando C# de este tipo, se podría hacer algo como:

type ObjectTypes = 
| TypeOne 
| TypeTwo 
| TypeThree 
... 
| TypeTwenty 
with override this.ToString() = 
    match this with 
    | TypeOne -> "This is type T123" 
    | TypeTwo -> "Oh man! This is type T234" 
    ... 
    | TypeTwenty -> "This is type last" 
    | _ -> "This is any other type that wasn't explicitly specified" 

Por supuesto, con F # coincidencia de patrones, usted tiene mucho más control de lo que haría con una simple instrucción switch C#.

Cuestiones relacionadas