Se eu tiver uma variável segurando uma enumeração de sinalizadores, posso de alguma forma iterar sobre os valores de bits nessa variável específica? Ou preciso usar Enum.GetValues para iterar toda a enumeração e verificar quais estão definidas?
c#
enums
enum-flags
Olivier Rogier
fonte
fonte
Respostas:
fonte
HasFlag
está disponível no .NET 4 em diante.Enum.GetValues(input.GetType()).Cast<Enum>().Where(input.HasFlag);
Em seguida, basta:myEnum.GetFLags()
:)static IEnumerable<Enum> GetFlags(this Enum input)
Aqui está uma solução Linq para o problema.
fonte
.Where(v => !Equals((int)(object)v, 0) && e.HasFlag(v));
se você tiver um valor zero para representarNone
Não existem métodos internos para obter cada componente, tanto quanto eu sei. Mas aqui está uma maneira de obtê-los:
Eu adaptei o que
Enum
faz internamente para gerar a string para retornar as bandeiras. Você pode ver o código no refletor e deve ser mais ou menos equivalente. Funciona bem para casos de uso geral em que existem valores que contêm vários bits.O método de extensão
GetIndividualFlags()
obtém todos os sinalizadores individuais para um tipo. Portanto, valores contendo vários bits são deixados de fora.fonte
Bar
,Baz
eBoo
não apenasBoo
.Boo
(o valor retornado usandoToString()
). Eu o ajustei para permitir apenas sinalizadores individuais. Então, no meu exemplo, você pode obterBar
e, emBaz
vez deBoo
.Voltando a isso alguns anos depois, com um pouco mais de experiência, minha resposta final apenas para valores de bit único, passando do bit mais baixo para o mais alto, é uma ligeira variante da rotina interna de Jeff Mercado:
Parece funcionar, e apesar das minhas objeções de alguns anos atrás, uso o HasFlag aqui, pois é muito mais legível do que usar comparações bit a bit e a diferença de velocidade é insignificante para qualquer coisa que eu esteja fazendo. (É perfeitamente possível que eles tenham melhorado a velocidade do HasFlags desde então, pelo que sei ... não testei.)
fonte
yield return bits;
?Saindo do método de Greg, mas adicionando um novo recurso do C # 7.3, a
Enum
restrição:A nova restrição permite que este seja um método de extensão, sem ter que transmitir
(int)(object)e
, e eu posso usar oHasFlag
método e transmitir diretamente paraT
fromvalue
.O C # 7.3 também adicionou restrições para delagates e
unmanaged
.fonte
flags
parâmetro também fosse do tipo genéricoT
, caso contrário, teria que especificar explicitamente o tipo de enum sempre que o chamar.+1 para a resposta fornecida por @ RobinHood70. Eu descobri que uma versão genérica do método era conveniente para mim.
EDIT E +1 para @AustinWBryan por trazer C # 7.3 para o espaço da solução.
fonte
Você não precisa iterar todos os valores. basta verificar suas bandeiras específicas da seguinte forma:
ou (como pstrjds disse nos comentários), você pode verificar se está usando:
fonte
O que fiz foi mudar minha abordagem, em vez de digitar o parâmetro de entrada do método como o
enum
tipo, digitei-o como uma matriz doenum
tipo (MyEnum[] myEnums
), dessa forma, apenas itero através da matriz com uma instrução switch dentro do loop.fonte
Não ficou satisfeito com as respostas acima, embora tenham sido o começo.
Depois de reunir algumas fontes diferentes aqui:
Pôster anterior no tópico SO QnA
Code Projeto Enum Flags Check Post
Great Enum <T> Utility
Eu criei isso, então deixe-me saber o que você pensa.
Parâmetros::
bool checkZero
diz para permitir0
como um valor de flag. Por padrão,input = 0
retorna vazio.bool checkFlags
: diz para verificar se oEnum
item está decorado com o[Flags]
atributoPS. Agora não tenho tempo para descobrir o
checkCombinators = false
alg que o forçará a ignorar quaisquer valores de enumeração que são combinações de bits.Isso usa o Enum de classe auxiliar <T> encontrado aqui que eu atualizei para usar
yield return
paraGetValues
:Finalmente, aqui está um exemplo de como usá-lo:
fonte
Com base na resposta de Greg acima, isso também trata do caso em que você tem um valor 0 na sua enumeração, como Nenhum = 0. Nesse caso, não deve iterar sobre esse valor.
Alguém saberia como melhorar isso ainda mais para que ele possa lidar com o caso em que todos os sinalizadores na enum são definidos de uma maneira super inteligente que possa lidar com todo o tipo de enum subjacente e o caso de All = ~ 0 e All = EnumValue1 | EnumValue2 | EnumValue3 | ...
fonte
Você pode usar um iterador do Enum. A partir do código MSDN:
Não foi testado, por isso, se eu cometer um erro, sinta-se à vontade para me chamar. (obviamente, não é reentrante.) Você teria que atribuir valor antecipadamente ou dividi-lo em outra função que use enum.dayflag e enum.days. Você pode ir a algum lugar com o esboço.
fonte
Também pode ser o seguinte código:
Ele entra se apenas quando o valor de enum estiver contido no valor
fonte
Todas as respostas funcionam bem com sinalizadores simples. Você provavelmente entrará em problemas quando os sinalizadores forem combinados.
provavelmente precisará adicionar uma verificação para testar se o valor da enumeração é uma combinação. Você provavelmente precisaria de algo como postado aqui por Henk van Boeijen para atender às suas necessidades (você precisa rolar um pouco)
fonte
Método de extensão usando a nova restrição e genéricos Enum para impedir a transmissão:
fonte
Você pode fazer isso diretamente convertendo para int, mas perderá a verificação de tipo. Eu acho que a melhor maneira é usar algo semelhante à minha proposição. Mantém o tipo adequado até o fim. Nenhuma conversão é necessária. Não é perfeito devido ao boxe, que adicionará um pequeno impacto no desempenho.
Não é perfeito (boxe), mas faz o trabalho sem aviso ...
Uso:
fonte