Pregunta

¿Alguien sabe cómo transformar un valor de enumeración en un valor legible por humanos?

Por ejemplo:

ThisIsValueA debería ser "Este es el valor A".

¿Fue útil?

Solución

Convirtiendo esto de un fragmento de código vb que un tal Ian Horwill dejó en una publicación de blog hace mucho tiempo...Desde entonces he usado esto en producción con éxito.

    /// <summary>
    /// Add spaces to separate the capitalized words in the string, 
    /// i.e. insert a space before each uppercase letter that is 
    /// either preceded by a lowercase letter or followed by a 
    /// lowercase letter (but not for the first char in string). 
    /// This keeps groups of uppercase letters - e.g. acronyms - together.
    /// </summary>
    /// <param name="pascalCaseString">A string in PascalCase</param>
    /// <returns></returns>
    public static string Wordify(string pascalCaseString)
    {            
        Regex r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
        return r.Replace(pascalCaseString, " ${x}");
    }

(requiere 'usar System.Text.RegularExpressions;')

De este modo:

Console.WriteLine(Wordify(ThisIsValueA.ToString()));

Volvería,

"This Is Value A".

Es mucho más simple y menos redundante que proporcionar atributos de descripción.

Los atributos son útiles aquí solo si necesita proporcionar una capa de indirección (que la pregunta no solicita).

Otros consejos

.ToString on Enums es relativamente lento en C#, comparable con GetType().Name (incluso podría usarlo bajo las sábanas).

Si su solución necesita ser muy rápida o altamente eficiente, lo mejor sería almacenar en caché sus conversiones en un diccionario estático y buscarlas desde allí.


Una pequeña adaptación del código de @Leon para aprovechar C#3.Esto tiene sentido como una extensión de las enumeraciones; puede limitar esto al tipo específico si no desea desordenarlos todos.

public static string Wordify(this Enum input)
{            
    Regex r = new Regex("(?<=[a-z])(?<x>[A-Z])|(?<=.)(?<x>[A-Z])(?=[a-z])");
    return r.Replace( input.ToString() , " ${x}");
}

//then your calling syntax is down to:
MyEnum.ThisIsA.Wordify();

La mayoría de los ejemplos de esto que he visto implican marcar los valores de enumeración con atributos [Descripción] y usar la reflexión para realizar la "conversión" entre el valor y la descripción.Aquí hay una antigua publicación de blog al respecto:

http://geekswithblogs.net/rakker/archive/2006/05/19/78952.aspx

Puede heredar de la clase "Atributo" de System.Reflection para crear su propia clase "Descripción".Así (de aquí):

using System;
using System.Reflection;
namespace FunWithEnum
{
    enum Coolness : byte
    {
        [Description("Not so cool")]
        NotSoCool = 5,
        Cool, // since description same as ToString no attr are used
        [Description("Very cool")]
        VeryCool = NotSoCool + 7,
        [Description("Super cool")]
        SuperCool
    }
    class Description : Attribute
    {
        public string Text;
        public Description(string text)
        {
            Text = text;
        }
    }
    class Program
    {
        static string GetDescription(Enum en)
        {
            Type type = en.GetType();
            MemberInfo[] memInfo = type.GetMember(en.ToString());
            if (memInfo != null && memInfo.Length > 0)
            {
                object[] attrs = memInfo[0].GetCustomAttributes(typeof(Description), false);
                if (attrs != null && attrs.Length > 0)
                    return ((Description)attrs[0]).Text;
            }
            return en.ToString();
        }
        static void Main(string[] args)
        {
            Coolness coolType1 = Coolness.Cool;
            Coolness coolType2 = Coolness.NotSoCool;
            Console.WriteLine(GetDescription(coolType1));
            Console.WriteLine(GetDescription(coolType2));
        }
    }
}

También puedes echar un vistazo a este artículo: http://www.codeproject.com/KB/cs/enumdatabinding.aspx

Se trata específicamente de enlace de datos, pero muestra cómo usar un atributo para decorar los valores de enumeración y proporciona un método "GetDescription" para recuperar el texto del atributo.El problema con el uso del atributo de descripción incorporado es que hay otros usos/usuarios de ese atributo, por lo que existe la posibilidad de que la descripción aparezca donde no desea.El atributo personalizado resuelve ese problema.

Me pareció mejor definir los valores de enumeración con una puntuación inferior para que ThisIsValueA sea This_Is_Value_A, luego puedes hacer un enumValue.toString().Replace("_"," ") donde enumValue es tu variable.

Una alternativa para agregar Description atributos a cada enumeración es crear un método de extensión.Para reutilizar la enumeración "Coolness" de Adam:

public enum Coolness
{
    NotSoCool,
    Cool,
    VeryCool,
    SuperCool
}

public static class CoolnessExtensions
{
    public static string ToString(this Coolness coolness)
    {
        switch (coolness)
        {
            case Coolness.NotSoCool:
                return "Not so cool";
            case Coolness.Cool:
                return "Cool";
            case Coolness.VeryCool:
                return "Very cool";
            case Coolness.SuperCool:
                return Properties.Settings.Default["SuperCoolDescription"].ToString();
            default:
                throw new ArgumentException("Unknown amount of coolness", nameof(coolness));
        }
    }
}

Aunque esto significa que las descripciones están más alejadas de los valores reales, le permite usar la localización para imprimir cadenas diferentes para cada idioma, como en mi VeryCool ejemplo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top