Infelizmente, as operações de enumeração de sinalizador do .NET são bastante limitadas. Na maioria das vezes, os usuários ficam com a lógica de operação bit a bit.
No .NET 4, HasFlag
foi adicionado o método Enum
que ajuda a simplificar o código do usuário, mas infelizmente há muitos problemas com ele.
HasFlag
não é seguro quanto ao tipo, pois aceita qualquer tipo de argumento de valor de enumeração, não apenas o tipo de enumeração especificado.
HasFlag
é ambíguo se verifica se o valor possui todos ou alguns dos sinalizadores fornecidos pelo argumento de valor da enumeração. É tudo a propósito.
HasFlag
é bastante lento, pois requer boxe, o que causa alocações e, portanto, mais coleta de lixo.
Em parte devido ao suporte limitado do .NET para enumerações de flag, escrevi a biblioteca OSS Enums.NET, que aborda cada um desses problemas e facilita muito o tratamento de enumerações de flag.
Abaixo estão algumas das operações que ele fornece, juntamente com suas implementações equivalentes, usando apenas a estrutura .NET.
Combinar sinalizadores
.INTERNET flags | otherFlags
Enums.NET flags.CombineFlags(otherFlags)
Remover sinalizadores
.INTERNET flags & ~otherFlags
Enums.NET flags.RemoveFlags(otherFlags)
Sinalizadores comuns
.INTERNET flags & otherFlags
Enums.NET flags.CommonFlags(otherFlags)
Alternar sinalizadores
.INTERNET flags ^ otherFlags
Enums.NET flags.ToggleFlags(otherFlags)
Tem todas as bandeiras
.NET (flags & otherFlags) == otherFlags
ouflags.HasFlag(otherFlags)
Enums.NET flags.HasAllFlags(otherFlags)
Tem sinalizadores
.INTERNET (flags & otherFlags) != 0
Enums.NET flags.HasAnyFlags(otherFlags)
Obter sinalizadores
.INTERNET
Enumerable.Range(0, 64)
.Where(bit => ((flags.GetTypeCode() == TypeCode.UInt64 ? (long)(ulong)flags : Convert.ToInt64(flags)) & (1L << bit)) != 0)
.Select(bit => Enum.ToObject(flags.GetType(), 1L << bit))`
Enums.NET flags.GetFlags()
Estou tentando incorporar essas melhorias no .NET Core e, eventualmente, no .NET Framework completo. Você pode conferir minha proposta aqui .