Pergunta

Alguém sabe como transformar um valor enum em um valor legível por humanos?

Por exemplo:

ThisIsValueA deve ser "Este é o valor A".

Foi útil?

Solução

Convertendo isso de um trecho de código vb que um certo Ian Horwill deixou em um postagem no blog há muito tempo...desde então, usei isso na produção com sucesso.

    /// <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}");
    }

(requer 'usando System.Text.RegularExpressions;')

Por isso:

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

Retornaria,

"This Is Value A".

É muito mais simples e menos redundante do que fornecer atributos de Descrição.

Os atributos são úteis aqui apenas se você precisar fornecer uma camada de indireção (que a pergunta não solicitou).

Outras dicas

O .ToString on Enums é relativamente lento em C#, comparável com GetType().Name (pode até usar isso nos bastidores).

Se sua solução precisa ser muito rápida ou altamente eficiente, talvez seja melhor armazenar em cache suas conversões em um dicionário estático e procurá-las a partir daí.


Uma pequena adaptação do código do @Leon para aproveitar as vantagens do C#3.Isso faz sentido como uma extensão de enums - você pode limitar isso ao tipo específico se não quiser desordenar todos eles.

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();

A maioria dos exemplos disso que vi envolve marcar seus valores enum com atributos [Descrição] e usar reflexão para fazer a "conversão" entre o valor e a descrição.Aqui está uma postagem antiga no blog sobre isso:

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

Você pode herdar da classe "Atributo" de System.Reflection para criar sua própria classe "Descrição".Assim (de aqui):

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));
        }
    }
}

Você também pode dar uma olhada neste artigo: http://www.codeproject.com/KB/cs/enumdatabinding.aspx

É especificamente sobre vinculação de dados, mas mostra como usar um atributo para decorar os valores enum e fornece um método "GetDescription" para recuperar o texto do atributo.O problema com o uso do atributo de descrição integrado é que existem outros usos/usuários desse atributo, portanto, existe a possibilidade de a descrição aparecer onde você não deseja.O atributo personalizado resolve esse problema.

Achei melhor definir seus valores de enum com uma pontuação inferior, então ThisIsValueA seria This_Is_Value_A, então você pode simplesmente fazer um enumValue.toString().Replace("_"," ") onde enumValue é sua variável.

Uma alternativa para adicionar Description atributos para cada enumeração é criar um método de extensão.Para reutilizar a enumeração "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));
        }
    }
}

Embora isso signifique que as descrições estão mais distantes dos valores reais, permite usar a localização para imprimir strings diferentes para cada idioma, como no meu VeryCool exemplo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top