De tempos em tempos, vejo um enum como o seguinte:
[Flags]
public enum Options
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option4 = 8
}
Não entendo exatamente o que o [Flags]
atributo faz.
Alguém tem uma boa explicação ou exemplo que poderia postar?
CatAndDog = Cat | Dog
(o OR lógico em vez do Condicional), presumo?Respostas:
O
[Flags]
atributo deve ser usado sempre que o enumerável representar uma coleção de valores possíveis, em vez de um único valor. Essas coleções são frequentemente usadas com operadores bit a bit, por exemplo:Observe que o
[Flags]
atributo não permite isso por si só - tudo o que faz é permitir uma boa representação pelo.ToString()
método:Também é importante notar que
[Flags]
não fazer automaticamente os valores ENUM potências de dois. Se você omitir os valores numéricos, a enumeração não funcionará como seria de esperar em operações bit a bit, porque, por padrão, os valores começam com 0 e incrementam.Declaração incorreta:
Os valores, se declarados dessa maneira, serão Amarelo = 0, Verde = 1, Vermelho = 2, Azul = 3. Isso o tornará inútil como sinalizadores.
Aqui está um exemplo de uma declaração correta:
Para recuperar os valores distintos em sua propriedade, é possível fazer o seguinte:
ou anterior ao .NET 4:
Debaixo das cobertas
Isso funciona porque você usou poderes de dois em sua enumeração. Nos bastidores, seus valores de enumeração são assim em zeros e binários:
Da mesma forma, depois de definir sua propriedade AllowedColors como Vermelho, Verde e Azul usando o
|
operador binário OR bit a bit , AllowedColors fica assim:Portanto, quando você recupera o valor, está realmente executando AND bit a bit
&
nos valores:O valor None = 0
E sobre o uso de
0
na sua enumeração, citando o MSDN:Você pode encontrar mais informações sobre o atributo flags e seu uso no msdn e sobre o design de flags no msdn
fonte
ToString
implementação de seu enum usa Flags, e assim fazEnum.IsDefined
,Enum.Parse
etc. Tente remover Bandeiras e olhar para o resultado de MyColor.Yellow | MyColor.Red; sem ele você obtém "5", com Flags você obtém "Amarelo, Vermelho". Algumas outras partes da estrutura também usam [Flags] (por exemplo, serialização XML).myProperties.AllowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;
. Você pode fazer:myProperties.AllowedColors = myProperties.AllowedColors ^ MyColor.Blue //myProperties.AllowedColors == MyColor.Red | Mycolor.Green
Você também pode fazer isso
Acho a mudança de bits mais fácil do que digitar 4,8,16,32 e assim por diante. Não tem impacto no seu código, porque tudo é feito em tempo de compilação
fonte
Third = Second << 1
, em vez deThird = 1 << 2
- ver descrição mais completa abaixo1 << 31 == -2147483648
,1 << 32 == 1
,1 << 33 == 2
e assim por diante. Por outro lado, se você dizThirtySecond = 2147483648
para um tipo int enum, o compilador gera um erro.Combinando as respostas https://stackoverflow.com/a/8462/1037948 (declaração via deslocamento de bits) e https://stackoverflow.com/a/9117/1037948 (usando combinações na declaração), você pode alterar os valores anteriores em vez de do que usar números. Não necessariamente recomendando, mas apenas apontando que você pode.
Ao invés de:
Você pode declarar
Confirmando com LinqPad:
Resulta em:
fonte
Consulte o seguinte para um exemplo que mostra a declaração e o uso potencial:
fonte
Em extensão à resposta aceita, em C # 7 os sinalizadores de enum podem ser escritos usando literais binários:
Eu acho que essa representação deixa claro como as bandeiras funcionam embaixo das cobertas .
fonte
0b_0100
Eu perguntei recentemente sobre algo semelhante.
Se você usar sinalizadores, poderá adicionar um método de extensão às enumerações para facilitar a verificação dos sinalizadores contidos (consulte a publicação para obter detalhes)
Isso permite que você faça:
Então você pode fazer:
Acho isso mais fácil de ler do que a maioria das maneiras de verificar os sinalizadores incluídos.
fonte
HasFlag
método para enumerações, de modo que você pode fazeropt.HasFlag( PossibleOptions.OptionOne )
sem ter que escrever suas próprias extensõesHasFlag
é muito mais lento que fazer operações bit a bit.@Nidonocu
Para adicionar outro sinalizador a um conjunto de valores existente, use o operador de atribuição OR.
fonte
Ao trabalhar com sinalizadores, muitas vezes declaro itens adicionais Nenhum e Todos. Isso é útil para verificar se todos os sinalizadores estão definidos ou se nenhum sinalizador está definido.
Uso:
Atualização 2019-10:
Desde o C # 7.0, você pode usar literais binários, provavelmente mais intuitivos de ler:
fonte
Para adicionar
Mode.Write
:fonte
Há algo excessivamente detalhado para mim sobre a
if ((x & y) == y)...
construção, especialmente sex
ANDy
são conjuntos compostos de sinalizadores e você só quer saber se há alguma sobreposição.Nesse caso, tudo o que você realmente precisa saber é se existe um valor diferente de zero [1] após a mascaragem .
Criando fora da configuração do @ andnil ...
fonte
enum
, precisaremos verificar!= 0
.Os sinalizadores permitem que você use máscaras de bits na sua enumeração. Isso permite combinar valores de enumeração, mantendo quais são especificados.
fonte
Desculpas se alguém já percebeu esse cenário. Um exemplo perfeito de bandeiras que podemos ver na reflexão. Sim Sinalizadores de ligação ENUM. https://docs.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=netframework-4.8
Uso
fonte