Converter Enum em String

163

Qual é a maneira preferida de converter um Enum em uma String no .NET 3.5?

  • Enum.GetName
  • Enum.Format
  • Para sequenciar

Por que devo preferir um deles ao invés dos outros? Alguém tem um desempenho melhor?

Eric Weilnau
fonte
10
Eu procurei e não consegui encontrar uma duplicata. Se você pode fornecer um link, eu excluirei esta pergunta.
Eric Weilnau 27/01/09
1
às vezes, usando uma instrução switch não é a melhor prática (quando você tem grandes enumerações) você pode usar Dict <> em vez
Guy L
1
Se você deseja um melhor desempenho, pode usar a classe descrita neste artigo codeproject.com/KB/dotnet/enum.aspx . Uso será parecido com este Enum <YourEnum> .ToString (yourValue) ou Enum <YourEnum> .ToString ((int) yourValue)
ideafixxxer
5
Codificar para não romper a difusão de pontos é o epítome da cauda que sacode o cão. Os produtores de SW não estão pensando: "Vamos criar um ótimo aplicativo para que o dotfuscator tenha algo a fazer". O Dofuscator existe para ajudar a facilitar o desenvolvimento do SW. Se não pode fazer isso ... pode!
Micahhoover

Respostas:

125

A partir do C # 6, a melhor maneira de obter o nome de uma enumeração é o novo nameofoperador:

nameof(MyEnum.EnumValue);

// Ouputs
> "EnumValue"

Isso funciona em tempo de compilação, com o enum sendo substituído pela string no resultado compilado, o que, por sua vez, significa que esta é a maneira mais rápida possível.

Qualquer uso de nomes de enumerações interfere na ofuscação do código, se você considerar que a ofuscação de nomes de enumerações vale a pena ou é importante - provavelmente essa é outra questão.

Keith
fonte
11
Isso merece mais atenção. Não obstante a limitação óbvia, ou seja, o requisito para entrada em tempo de compilação. Na minha opinião, isso deve ser preferido sempre que possível . 'Renomear' e 'encontrar todas as referências' também levam em conta, potencialmente evitando seqüências de caracteres mágicas e constantes duplicadas.
Timo
1
Então eu acho que não vai funcionar quando o valor de enum é definido em tempo de execução? Ex: MyEnum variableEnum; variableEnum = setEnumValueMethod (); nameof (variávelEnum);
Maxter
1
@ Maxter não, como nameof(variableEnum)será "variableEnum". Ele reflete (no tempo de construção) o nome do campo / propriedade / parâmetro / variável e não o valor .
Keith
vós. infelizmente não funciona se você fizer isso: var someEnumvalue = SomeEnum.FooBar; nameof (someEnumvalue);
Squibly 11/11/19
@Squibly sim, que irá retornar "someEnumValue", enquanto você precisaria nameof(SomeEnum.FooBar)para chegar "FooBar".
21419 Keith
93

Trabalha para o nosso projeto ...

public static String convertToString(this Enum eff)
{
    return Enum.GetName(eff.GetType(), eff);
}

public static EnumType converToEnum<EnumType>(this String enumValue)  
{
    return (EnumType) Enum.Parse(typeof(EnumType), enumValue);
}
Sumtraveller
fonte
7
Enum.GetName leva o valor como um argumento de objeto. Isso significa que o valor será armazenado em caixa e isso desperdiçará recursos da CPU na alocação e na coleta de lixo. Se isso for feito muito tempo, o Enum.GetName terá uma taxa de transferência muito menor do que o cache dos valores em um dicionário e a procura do nome lá.
Ran
@Ran Então, qual é a solução, qual usar?
shaijut
Esta deve ser a resposta
Squibly
torna meu projeto mais lento. toString () é mais rápido.
d2k2 15/06
29

Nos meus testes, Enum.GetNamefoi mais rápido e com margem decente. ToStringChamadas internamente Enum.GetName. Da fonte para o .NET 4.0, o essencial:

public override String ToString()
{
     return Enum.InternalFormat((RuntimeType)GetType(), GetValue());
}

private static String InternalFormat(RuntimeType eT, Object value)
{
    if (!eT.IsDefined(typeof(System.FlagsAttribute), false))
    {
        String retval = GetName(eT, value); //<== the one
        if (retval == null)
            return value.ToString();
        else
            return retval;
    }
    else
    {
        return InternalFlagsFormat(eT, value);
    }
}

Não posso dizer que esse seja o motivo, com certeza, mas os testes indicam que um é mais rápido que o outro. Ambas as chamadas envolvem boxe (na verdade, são chamadas de reflexão, você está basicamente recuperando nomes de campos) e pode ser lento ao seu gosto.

Configuração do teste : enumeração com 8 valores, no. de iterações = 1000000

Resultado : Enum.GetName => 700 ms, ToString => 2000 ms

Se a velocidade não for perceptível, eu não me importaria e usaria, ToStringpois oferece uma chamada muito mais limpa. Contraste

Enum.GetName(typeof(Bla), value)

com

value.ToString()
nawfal
fonte
25

Enum.GetName (...)

Este é o método mais elegante para isso.

var enumValueString = Enum.GetName(typeof (MyEnum), MyEnum.MyValue);

Embora eu não veja nenhum problema com a chamada .ToString(), ela é simplesmente mais curta.

var enumValueString = MyEnum.MyValue.ToString();

Com a nova sintaxe C # 6, você pode usar:

nameof(MyEnum.MyValue)
Andrei
fonte
20

Tudo isso internamente acaba chamando um método chamado InternalGetValueAsString. A diferença entre ToStringe GetNameseria a que GetNamedeve verificar algumas coisas primeiro:

  1. O tipo digitado não é nulo.
  2. O tipo que você digitou é, de fato, uma enumeração.
  3. O valor que você passou não é nulo.
  4. O valor que você passou é de um tipo que uma enumeração pode realmente usar como tipo subjacente ou do tipo da própria enumeração. Ele usa GetTypeo valor para verificar isso.

.ToStringnão precisa se preocupar com nenhum desses problemas acima, porque é chamado em uma instância da própria classe e não em uma versão passada, portanto, devido ao fato de o .ToStringmétodo não ter os mesmos problemas de verificação como métodos estáticos, eu concluiria que .ToStringé a maneira mais rápida de obter o valor como uma string.

David Morton
fonte
2
onde você verificou isso? Qual era a versão da montagem? Eu recebo resultados muito diferentes.
Nawfal
17

O melhor que posso encontrar é essa pergunta não relacionada no MSDN , que contém um trecho de código XML que responde a essa pergunta. Qualquer um desses métodos compartilha a mesma falha: eles chamam enum.toString(), o que não funciona corretamente ao usar o Dotfuscation . Outras preocupações parecem estar relacionadas ao boxe indireto (GetName e Format). Infelizmente, não consigo encontrar nenhuma razão de desempenho para usar qualquer uma das opções acima.

Parafraseando do snippet xml ,

Passar uma enumeração em caixa para string.Format () ou qualquer outra função pode resultar em enum.ToString()uma chamada. Isso causará problemas quando o Dotfuscating. Você não deve usar enum.ToString(), enum.GetNames(), enum.GetName(), enum.Format()ou enum.Parse()para converter um enum para uma string. Em vez disso, use uma instrução switch e internacionalize os nomes, se necessário.

jpaugh
fonte
16

Enum.GetName()

Format()é realmente apenas um invólucro GetName()com alguma funcionalidade de formatação (ou InternalGetValueAsString()para ser exato). ToString()é praticamente o mesmo que Format(). Eu acho que GetName()é a melhor opção, pois é totalmente óbvio o que faz para quem lê a fonte.

Tamas Czinege
fonte
8

Crio um método de extensão "Descrição" e o anexo à enumeração para que eu possa obter uma nomeação verdadeiramente amigável que inclua espaços e maiúsculas e minúsculas. Eu nunca gostei de usar o valor enum como texto exibível porque é algo que os desenvolvedores usam para criar um código mais legível. Não se destina a fins de exibição da interface do usuário. Quero poder alterar a interface do usuário sem passar e alterar as enumerações por toda parte.

DançasComBambu
fonte
6

Não sei qual é o método "preferido" (pergunte a 100 pessoas e obtenha 100 opiniões diferentes), mas faça o que é mais simples e o que funciona. GetNamefunciona, mas requer muito mais pressionamentos de tecla. ToString()parece fazer o trabalho muito bem.

Perry Neal
fonte
1

Para os aficionados por VB:

EnumStringValue = System.Enum.GetName(GetType(MyEnum), MyEnumValue)
GlennG
fonte
0

Isso também funcionaria.

    List<string> names = Enum.GetNames(typeof(MyEnum)).ToList();
Nic
fonte
0

ToString()fornece o resultado mais óbvio do ponto de vista da legibilidade, enquanto usaEnum.GetName() requer uma análise um pouco mais mental para entender rapidamente o que está tentando fazer (a menos que você veja o padrão o tempo todo).

Do ponto de vista do desempenho puro, como já fornecido na resposta do @ nawfal, Enum.GetName()é melhor.

Se o desempenho é realmente o seu objetivo, seria ainda melhor fornecer uma pesquisa prévia (usando um Dicionário ou outro mapeamento).

Em C ++ / CLI, isso seria semelhante

Dictionary<String^, MyEnum> mapping;
for each (MyEnum field in Enum::GetValues(MyEnum::typeid))
{
    mapping.Add(Enum::GetName(MyEnum::typeid), field);
}

Comparação usando uma enumeração de 100 itens e 1000000 iterações:

Enum.GetName: ~
800ms .ToString (): ~ 1600ms
Mapeamento de dicionário: ~ 250ms

John Go-Soco
fonte
-2

Simples: enum nomes em uma lista:

List<String> NameList = Enum.GetNames(typeof(YourEnumName)).Cast<string>().ToList()
Brian
fonte
Oi @ Brian, eu não acho que você precisa para lançar a saída de GetNames ()
Nic