Eu tenho a seguinte enumeração:
public enum AuthenticationMethod
{
FORMS = 1,
WINDOWSAUTHENTICATION = 2,
SINGLESIGNON = 3
}
O problema, porém, é que eu preciso da palavra "FORMS" quando solicito o AuthenticationMethod.FORMS e não o ID 1.
Encontrei a seguinte solução para este problema ( link ):
Primeiro, preciso criar um atributo personalizado chamado "StringValue":
public class StringValue : System.Attribute
{
private readonly string _value;
public StringValue(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
}
Então eu posso adicionar este atributo ao meu enumerador:
public enum AuthenticationMethod
{
[StringValue("FORMS")]
FORMS = 1,
[StringValue("WINDOWS")]
WINDOWSAUTHENTICATION = 2,
[StringValue("SSO")]
SINGLESIGNON = 3
}
E é claro que preciso de algo para recuperar esse 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;
}
}
Bom agora eu tenho as ferramentas para obter um valor de string para um enumerador. Posso então usá-lo assim:
string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);
Ok, agora tudo isso funciona como um encanto, mas acho muito trabalho. Fiquei me perguntando se existe uma solução melhor para isso.
Eu também tentei algo com um dicionário e propriedades estáticas, mas isso também não foi melhor.
this
na frente doEnum
método estático. Então você pode fazerAuthenticationMethod.Forms.GetStringValue();
Respostas:
Experimente o padrão de enumeração segura .
A conversão de tipo explícito (ou implícito) da atualização pode ser feita por
adicionando campo estático com mapeamento
preenchendo esse mapeamento no construtor de instância
e adicionando operador de conversão de tipo definido pelo usuário
fonte
Use método
como em (Assume que
Shipper
é um Enum definido)Também existem muitos outros métodos estáticos na classe Enum que vale a pena investigar ...
fonte
Você pode referenciar o nome em vez do valor usando ToString ()
A documentação está aqui:
http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx
... e se você nomear suas enumerações em Pascal Case (como eu - como ThisIsMyEnumValue = 1 etc.), você poderá usar uma regex muito simples para imprimir o formulário amigável:
que pode ser facilmente chamado de qualquer string:
Saídas:
Isso evita correr ao redor das casas, criando atributos personalizados e anexando-os às suas enumerações ou usando tabelas de pesquisa para casar um valor de enumeração com uma string amigável e, o melhor de tudo, é autogerenciado e pode ser usado em qualquer string Pascal Case que seja infinitamente mais reutilizável. Obviamente, ele não permite que você tenha um nome amigável diferente do seu enum, que sua solução fornece.
Porém, eu gosto da sua solução original para cenários mais complexos. Você poderia levar sua solução um passo adiante e tornar seu GetStringValue um método de extensão de sua enumeração e não precisaria fazer referência a ela como StringEnum.GetStringValue ...
Você pode acessá-lo facilmente diretamente da sua instância enum:
fonte
"(?!^)([^A-Z])([A-Z])", "$1 $2"
. EntãoHereIsATEST
se tornaHere Is ATEST
.Infelizmente, a reflexão para obter atributos nas enumerações é bastante lenta:
Veja esta pergunta: Alguém conhece uma maneira rápida de obter atributos personalizados em um valor enum?
O
.ToString()
enums também é bastante lento.Você pode escrever métodos de extensão para enumerações:
Isso não é ótimo, mas será rápido e não exigirá a reflexão de atributos ou nome do campo.
Atualização C # 6
Se você pode usar o C # 6, o novo
nameof
operador trabalha para enumerações, entãonameof(MyEnum.WINDOWSAUTHENTICATION)
será convertido"WINDOWSAUTHENTICATION"
em tempo de compilação , tornando-a a maneira mais rápida de obter nomes de enumerações.Observe que isso converterá a enum explícita em uma constante embutida, para que não funcione nas enumerações que você possui em uma variável. Assim:
Mas...
fonte
Eu uso um método de extensão:
Agora decore o
enum
com:Quando Você ligar
AuthenticationMethod.FORMS.ToDescription()
você receberá"FORMS"
.fonte
using System.ComponentModel;
Além disso, esse método só funciona se você quiser que o valor String seja igual ao nome do Enum. O OP queria um valor diferente.AuthenticationMethod.FORMS.ToDescription()
?Basta usar o
ToString()
métodoPara referenciar a string
Tomato
, basta usarfonte
.ToString()
valor diferente do valor de fácil utilização que você precisa.any fruit = any.Tomato;
string tomato = fruit.ToString();
Solução muito simples para isso com .Net 4.0 e superior. Nenhum outro código é necessário.
Para obter a string apenas use:
ou
O valor será "Ativo" ou "Arquivado".
Para ver os diferentes formatos de sequência de caracteres (o "f" acima) ao chamar,
Enum.ToString
consulte esta página Sequências de formato de enumeraçãofonte
Eu uso o atributo Descrição do espaço para nome System.ComponentModel. Simplesmente decore a enum e use este código para recuperá-lo:
Como um exemplo:
Esse código atende muito bem às enumerações em que você não precisa de um "Nome amigável" e retornará apenas o .ToString () da enumeração.
fonte
Eu realmente gosto da resposta de Jakub Šturc, mas sua desvantagem é que você não pode usá-la com uma declaração de caso de mudança. Aqui está uma versão ligeiramente modificada de sua resposta que pode ser usada com uma instrução switch:
Portanto, você obtém todos os benefícios da resposta de Jakub Šturc, além de podermos usá-la com uma instrução switch da seguinte maneira:
fonte
public static int nextAvailable { get; private set; }
, no construtorthis.Value = nextAvailable++;
=
operador para permitir que a chave funcione? Eu fiz isso no VB e agora posso usá-lo naselect case
declaração.Eu uso uma combinação de várias das sugestões acima, combinadas com algum cache. Agora, peguei a ideia de algum código que encontrei em algum lugar na rede, mas não consigo me lembrar de onde o encontrei ou o encontrei. Portanto, se alguém encontrar algo parecido, comente com a atribuição.
De qualquer forma, o uso envolve os conversores de tipo, portanto, se você está vinculando à interface do usuário, 'simplesmente funciona'. Você pode estender o padrão de Jakub para pesquisa rápida de código, inicializando do conversor de tipo nos métodos estáticos.
O uso base ficaria assim
O código para o conversor de tipo de enum personalizado segue:
}
fonte
Na sua pergunta, você nunca disse que realmente precisa do valor numérico da enum em qualquer lugar.
Se você não precisa e apenas precisa de um enum do tipo string (que não é um tipo integral, portanto não pode ser uma base de enum), aqui está uma maneira:
você pode usar a mesma sintaxe que a enum para fazer referência a ela
Será um pouco mais lento do que com valores numéricos (comparando cadeias em vez de números), mas no lado positivo não está usando reflexão (lenta) para acessar a cadeia.
fonte
Como eu resolvi isso como um método de extensão:
Enum:
Uso (onde o.OrderType é uma propriedade com o mesmo nome da enumeração):
O que me dá uma sequência de "Novo cartão" ou "Recarregar" em vez do valor real da enumeração NewCard e Refill.
fonte
Atualização: visitar esta página, 8 anos depois, depois de não tocar em C # por um longo tempo, parece que minha resposta não é mais a melhor solução. Eu realmente gosto da solução de conversor vinculada às funções de atributo.
Se você estiver lendo isso, verifique também outras respostas.
(dica: eles estão acima deste)
Como muitos de vocês, gostei muito da resposta selecionada de Jakub Šturc , mas também odeio copiar e colar códigos e tentar fazê-lo o mínimo possível.
Então, decidi que queria uma classe EnumBase da qual a maior parte da funcionalidade é herdada / incorporada, deixando-me focar no conteúdo em vez do comportamento.
O principal problema dessa abordagem baseia-se no fato de que, embora os valores de Enum sejam instâncias de tipo seguro, a interação é com a implementação estática do tipo de classe Enum. Então, com uma pequena ajuda de magia genérica, acho que finalmente consegui a combinação correta. Espero que alguém ache isso tão útil quanto eu.
Vou começar com o exemplo de Jakub, mas usando herança e genéricos:
E aqui está a classe base:
fonte
Concordo com Keith, mas ainda não posso votar.
Eu uso um método estático e uma declaração swith para retornar exatamente o que eu quero. No banco de dados, armazeno tinyint e meu código usa apenas a enumeração real, portanto, as strings são para requisitos de interface do usuário. Após numerosos testes, isso resultou no melhor desempenho e maior controle sobre a saída.
No entanto, por algumas contas, isso leva a um possível pesadelo de manutenção e a algum cheiro de código. Eu tento ficar de olho em enums que são longas e muitas, ou que mudam com frequência. Caso contrário, esta tem sido uma ótima solução para mim.
fonte
Se você veio aqui procurando implementar um "Enum" simples, mas cujos valores são cadeias de caracteres em vez de ints, aqui está a solução mais simples:
Implementação:
fonte
static readonly
.Quando me deparo com esse problema, há algumas perguntas para as quais tento encontrar as respostas primeiro:
A maneira mais simples de fazer isso é com
Enum.GetValue
(e suporta o uso de round-tripEnum.Parse
). Também vale a pena construir umTypeConverter
, como sugere Steve Mitcham, para suportar a ligação à interface do usuário. (Não é necessário criar umTypeConverter
quando você estiver usando folhas de propriedades, o que é uma das coisas boas sobre folhas de propriedades. Embora o senhor saiba que eles têm seus próprios problemas.)Em geral, se as respostas às perguntas acima sugerem que isso não vai funcionar, meu próximo passo é criar e preencher uma estática
Dictionary<MyEnum, string>
, ou possivelmente umaDictionary<Type, Dictionary<int, string>>
. Costumo ignorar a etapa intermediária de decorar o código com atributos, porque o que geralmente vem a seguir é a necessidade de alterar os valores amigáveis após a implantação (geralmente, mas nem sempre, devido à localização).fonte
Eu queria postar isso como um comentário na postagem citada abaixo, mas não pude porque não tenho representante suficiente - por isso, não faça votos negativos. O código continha um erro e eu queria apontar isso para as pessoas que tentam usar esta solução:
deveria estar
Brilhante!
fonte
Minha variante
O código parece um pouco feio, mas o uso dessa estrutura é bastante representativo.
Além disso, acho que, se muitas dessas enumerações forem necessárias, a geração de código (por exemplo, T4) pode ser usada.
fonte
Opção 1:
e depois
Opção 2:
fonte
Se você pensa no problema que estamos tentando resolver, não é um enum que precisamos. Precisamos de um objeto que permita que um certo número de valores seja associado um ao outro; em outras palavras, para definir uma classe.
O padrão de enumeração de tipo seguro de Jakub Šturc é a melhor opção que vejo aqui.
Olhe para isso:
fonte
para mim, a abordagem pragmática é classe dentro da classe, exemplo:
fonte
Eu criei uma classe base para criar enumerações com valor de string no .NET. É apenas um arquivo C # que você pode copiar e colar em seus projetos ou instalar via pacote NuGet chamado StringEnum . Repositório do GitHub
<completitionlist>
. (Funciona em C # e VB)Instalação:
.Net Standard 1.0
para que seja executado em.Net Core
> = 1.0,.Net Framework
> = 4.5,Mono
> = 4.6, etc.fonte
Aqui está outra maneira de realizar a tarefa de associar seqüências de caracteres a enumerações:
Este método é chamado assim:
Você pode agrupar enumerações relacionadas em sua própria estrutura. Como esse método usa o tipo de enumeração, você pode usar o Intellisense para exibir a lista de enumerações ao fazer a
GetString()
chamada.Opcionalmente, você pode usar o novo operador na
DATABASE
estrutura. Não usá-lo significa que as seqüências de caracteresList
não são alocadas até que a primeiraGetString()
chamada seja feita.fonte
Muitas ótimas respostas aqui, mas no meu caso não resolveram o que eu queria de um "enum de string", que era:
1,2 e 4 podem realmente ser resolvidos com um Typedef C # de uma string (uma vez que strings são selecionáveis em c #)
3 pode ser resolvido por seqüências const estáticas. Portanto, se você tiver as mesmas necessidades, esta é a abordagem mais simples:
Isso permite, por exemplo:
e
Onde CreateType pode ser chamado com uma sequência ou um tipo. No entanto, a desvantagem é que qualquer string é automaticamente um enum válido , isso pode ser modificado, mas isso exigiria algum tipo de função init ... ou possivelmente tornaria explícita a conversão interna?
Agora, se um valor int foi importante para você (talvez para velocidade de comparação), você pode usar algumas idéias da fantástica resposta de Jakub Šturc e fazer algo um pouco louco, esta é a minha facada:
mas é claro "Tipos bob = 4;" não teria sentido a menos que você os tivesse inicializado primeiro, o que meio que derrotaria o argumento ...
Mas, em teoria, TypeA == TypeB seria mais rápido ...
fonte
Se estou entendendo corretamente, você pode simplesmente usar .ToString () para recuperar o nome da enumeração do valor (supondo que ela já seja convertida como enumeração); Se você teve o int nu (digamos, de um banco de dados ou algo assim), primeiro você pode convertê-lo no enum. Ambos os métodos abaixo receberão o nome da enumeração.
Lembre-se, porém, a segunda técnica assume que você está usando ints e seu índice é baseado em 1 (não em 0). A função GetNames também é bastante pesada em comparação, você está gerando uma matriz inteira cada vez que é chamada. Como você pode ver na primeira técnica, .ToString () é realmente chamado implicitamente. Ambos já foram mencionados nas respostas, é claro, só estou tentando esclarecer as diferenças entre eles.
fonte
post antigo, mas ...
A resposta para isso pode ser realmente muito simples. Use a função Enum.ToString ()
Existem 6 sobrecargas dessa função, você pode usar Enum.Tostring ("F") ou Enum.ToString () para retornar o valor da string. Não há necessidade de se preocupar com mais nada. Aqui está uma demonstração de trabalho
Observe que esta solução pode não funcionar para todos os compiladores ( esta demonstração não funciona conforme o esperado ), mas pelo menos funciona para o compilador mais recente.
fonte
com base no MSDN: http://msdn.microsoft.com/en-us/library/cc138362.aspx
str serão os nomes dos campos
fonte
Bem, depois de ler todas as opções acima, sinto que os caras complicaram demais a questão de transformar enumeradores em strings. Gostei da ideia de ter atributos sobre campos enumerados, mas acho que esses atributos são usados principalmente para metadados, mas no seu caso, acho que tudo que você precisa é algum tipo de localização.
Agora, se tentarmos chamar o método acima, podemos chamá-lo desta maneira
Tudo que você precisa fazer é apenas criar um arquivo de recursos contendo todos os valores do enumerador e as seqüências correspondentes
O que é realmente muito bom nisso é que será muito útil se você precisar que seu aplicativo seja localizado, pois tudo o que você precisa fazer é criar outro arquivo de recurso com seu novo idioma! e Voe-la!
fonte
Quando estou em uma situação como essa, proponho a solução abaixo.
E como uma classe consumidora, você poderia ter
E usando um dicionário bidirecional: com base nisso ( https://stackoverflow.com/a/255638/986160 ), assumindo que as chaves serão associadas a valores únicos no dicionário e semelhantes a ( https://stackoverflow.com/a / 255630/986160 ), mas um pouco mais elegante. Este dicionário também é enumerável e você pode ir e voltar de ints para strings. Além disso, você não precisa ter nenhuma string na sua base de código, com exceção desta classe.
fonte
Para conjuntos de enumerações de string maiores, os exemplos listados podem se tornar cansativos. Se você deseja uma lista de códigos de status ou outras enumerações baseadas em strings, um sistema de atributos é chato de usar e uma classe estática com instâncias próprias é chata de configurar. Para minha própria solução, utilizo o modelo T4 para facilitar a enumeração por string. O resultado é semelhante ao modo como a classe HttpMethod funciona.
Você pode usá-lo assim:
Você começa com um arquivo Enum.tt.
Em seguida, você adiciona seu arquivo StringEnum.ttinclude.
Por fim, você recompila o arquivo Enum.tt e a saída fica assim:
fonte