System.FlagsAttribute classe

Observação

Este artigo fornece observações complementares à documentação de referência para esta API.

O FlagsAttribute atributo indica que uma enumeração pode ser tratada como um campo bit, ou seja, um conjunto de sinalizadores.

Os campos de bit são geralmente usados para listas de elementos que podem ocorrer em combinação, enquanto as constantes de enumeração são geralmente usadas para listas de elementos mutuamente exclusivos. Portanto, os campos de bits são projetados para serem combinados com uma operação bitwise OR para gerar valores sem nome, enquanto as constantes enumeradas não têm essa finalidade. Os idiomas variam no uso de campos de bits em comparação com constantes de enumeração.

Atributos do FlagsAttribute

AttributeUsageAttribute é aplicado a essa classe e sua Inherited propriedade especifica false. Este atributo só pode ser aplicado a enumerações.

Diretrizes para FlagsAttribute e enum

  • Use o atributo personalizado FlagsAttribute para uma enumeração somente se uma operação bit a bit (AND, OR, EXCLUSIVE OR) deve ser executada em um valor numérico.

  • Defina constantes de enumeração em potências de dois, ou seja, 1, 2, 4, 8 e assim por diante. Isso significa que os sinalizadores individuais em constantes de enumeração combinadas não se sobrepõem.

  • Considere a criação de uma constante enumerada para combinações de sinalizadores comumente usadas. Por exemplo, se você tiver uma enumeração usada para operações de E/S de arquivo que contenha as constantes enumeradas Read = 1 e Write = 2, considere criar a constante enumerada ReadWrite = Read OR Write, que combina os sinalizadores Read e Write. Além disso, a operação OR bit a bit usada para combinar os sinalizadores pode ser considerada um conceito avançado em algumas circunstâncias, não devendo ser necessário para tarefas simples.

  • Tenha cuidado se definir um número negativo como uma constante enumerada de sinalizador, pois muitas posições de sinalizador podem ser definidas como 1, o que pode tornar seu código confuso e incentivar erros de codificação.

  • Uma maneira conveniente de testar se um sinalizador é definido em um valor numérico é executar uma operação AND bit a bit entre o valor numérico e a constante enumerada do sinalizador, que define todos os bits no valor numérico como zero que não correspondem ao sinalizador e, em seguida, testar se o resultado dessa operação é igual à constante enumerada do sinalizador.

  • Use None como o nome da constante enumerada do sinalizador cujo valor é zero. Não é possível usar a constante enumerada None em uma operação bit a bit AND para testar um sinalizador porque o resultado é sempre zero. No entanto, você pode executar uma comparação lógica, não bitwise, entre o valor numérico e a constante None enumerada para determinar se algum bit no valor numérico está definido.

    Se você criar uma enumeração de valor em vez de uma enumeração de sinalizadores, ainda valerá a pena criar uma None constante enumerada. O motivo é que, por padrão, a memória usada para a enumeração é inicializada para zero pelo common language runtime. Consequentemente, se você não definir uma constante cujo valor é zero, a enumeração conterá um valor ilegal quando for criada.

    Se houver um caso padrão óbvio que seu aplicativo precisa representar, considere usar uma constante enumerada cujo valor é zero para representar o padrão. Se não houver nenhum caso padrão, considere usar uma constante enumerada cujo valor é zero, o que significa o caso que não é representado por nenhuma das outras constantes enumeradas.

  • Não defina um valor de enumeração apenas para espelhar o estado da própria enumeração. Por exemplo, não defina uma constante enumerada que apenas marque o final da enumeração. Se você precisar determinar o último valor da enumeração, verifique esse valor explicitamente. Além disso, você pode executar uma verificação de intervalo para a primeira e a última constante enumerada se todos os valores dentro do intervalo forem válidos.

  • Não especifique constantes enumeradas que são reservadas para uso futuro.

  • Ao definir um método ou propriedade que usa uma constante enumerada como um valor, considere validar o valor. O motivo é que você pode converter um valor numérico para o tipo de enumeração, mesmo que esse valor numérico não esteja definido na enumeração.

Exemplos

O exemplo a seguir ilustra o uso do atributo FlagsAttribute e mostra o efeito no método ToString de utilizar FlagsAttribute numa declaração Enum.

using System;

class Example
{
    // Define an Enum without FlagsAttribute.
    enum SingleHue : short
    {
        None = 0,
        Black = 1,
        Red = 2,
        Green = 4,
        Blue = 8
    };

    // Define an Enum with FlagsAttribute.
    [Flags]
    enum MultiHue : short
    {
        None = 0,
        Black = 1,
        Red = 2,
        Green = 4,
        Blue = 8
    };

    static void Main()
    {
        // Display all possible combinations of values.
        Console.WriteLine(
             "All possible combinations of values without FlagsAttribute:");
        for (int val = 0; val <= 16; val++)
            Console.WriteLine("{0,3} - {1:G}", val, (SingleHue)val);

        // Display all combinations of values, and invalid values.
        Console.WriteLine(
             "\nAll possible combinations of values with FlagsAttribute:");
        for (int val = 0; val <= 16; val++)
            Console.WriteLine("{0,3} - {1:G}", val, (MultiHue)val);
    }
}
// The example displays the following output:
//       All possible combinations of values without FlagsAttribute:
//         0 - None
//         1 - Black
//         2 - Red
//         3 - 3
//         4 - Green
//         5 - 5
//         6 - 6
//         7 - 7
//         8 - Blue
//         9 - 9
//        10 - 10
//        11 - 11
//        12 - 12
//        13 - 13
//        14 - 14
//        15 - 15
//        16 - 16
//
//       All possible combinations of values with FlagsAttribute:
//         0 - None
//         1 - Black
//         2 - Red
//         3 - Black, Red
//         4 - Green
//         5 - Black, Green
//         6 - Red, Green
//         7 - Black, Red, Green
//         8 - Blue
//         9 - Black, Blue
//        10 - Red, Blue
//        11 - Black, Red, Blue
//        12 - Green, Blue
//        13 - Black, Green, Blue
//        14 - Red, Green, Blue
//        15 - Black, Red, Green, Blue
//        16 - 16
open System

// Define an Enum without FlagsAttribute.
type SingleHue =
    | None = 0
    | Black = 1
    | Red = 2
    | Green = 4
    | Blue = 8

// Define an Enum with FlagsAttribute.
[<Flags>]
type MultiHue =
    | None = 0
    | Black = 1
    | Red = 2
    | Green = 4
    | Blue = 8

// Display all possible combinations of values.
printfn "All possible combinations of values without FlagsAttribute:"
for i = 0 to 16 do
    printfn $"{i,3} - {enum<SingleHue> i:G}"

// Display all combinations of values, and invalid values.
printfn "\nAll possible combinations of values with FlagsAttribute:"
for i = 0 to 16 do
    printfn $"{i,3} - {enum<MultiHue> i:G}"

// The example displays the following output:
//       All possible combinations of values without FlagsAttribute:
//         0 - None
//         1 - Black
//         2 - Red
//         3 - 3
//         4 - Green
//         5 - 5
//         6 - 6
//         7 - 7
//         8 - Blue
//         9 - 9
//        10 - 10
//        11 - 11
//        12 - 12
//        13 - 13
//        14 - 14
//        15 - 15
//        16 - 16
//
//       All possible combinations of values with FlagsAttribute:
//         0 - None
//         1 - Black
//         2 - Red
//         3 - Black, Red
//         4 - Green
//         5 - Black, Green
//         6 - Red, Green
//         7 - Black, Red, Green
//         8 - Blue
//         9 - Black, Blue
//        10 - Red, Blue
//        11 - Black, Red, Blue
//        12 - Green, Blue
//        13 - Black, Green, Blue
//        14 - Red, Green, Blue
//        15 - Black, Red, Green, Blue
//        16 - 16
Module Example
   ' Define an Enum without FlagsAttribute.
   Enum SingleHue As Short
      None = 0
      Black = 1
      Red = 2
      Green = 4
      Blue = 8
   End Enum

   ' Define an Enum with FlagsAttribute.
   <Flags()> 
   Enum MultiHue As Short
      None = 0
      Black = 1
      Red = 2
      Green = 4
      Blue = 8
   End Enum

   Sub Main()
      ' Display all possible combinations of values.
      Console.WriteLine(
           "All possible combinations of values without FlagsAttribute:")
      For val As Integer = 0 To 16
         Console.WriteLine("{0,3} - {1:G}", val, CType(val, SingleHue))
     Next 
     Console.WriteLine()
     
     ' Display all combinations of values, and invalid values.
     Console.WriteLine( 
          "All possible combinations of values with FlagsAttribute:")
     For val As Integer = 0 To 16
        Console.WriteLine( "{0,3} - {1:G}", val, CType(val, MultiHue))
     Next 
   End Sub 
End Module 
' The example displays the following output:
'       All possible combinations of values without FlagsAttribute:
'         0 - None
'         1 - Black
'         2 - Red
'         3 - 3
'         4 - Green
'         5 - 5
'         6 - 6
'         7 - 7
'         8 - Blue
'         9 - 9
'        10 - 10
'        11 - 11
'        12 - 12
'        13 - 13
'        14 - 14
'        15 - 15
'        16 - 16
'       
'       All possible combinations of values with FlagsAttribute:
'         0 - None
'         1 - Black
'         2 - Red
'         3 - Black, Red
'         4 - Green
'         5 - Black, Green
'         6 - Red, Green
'         7 - Black, Red, Green
'         8 - Blue
'         9 - Black, Blue
'        10 - Red, Blue
'        11 - Black, Red, Blue
'        12 - Green, Blue
'        13 - Black, Green, Blue
'        14 - Red, Green, Blue
'        15 - Black, Red, Green, Blue
'        16 - 16

O exemplo anterior define duas enumerações SingleHue relacionadas a cores e MultiHue. O segundo tem o FlagsAttribute atributo, o primeiro não. O exemplo mostra a diferença no comportamento quando um intervalo de inteiros, incluindo aqueles que não representam valores subjacentes do tipo de enumeração, é convertido para o tipo de enumeração e suas representações em cadeia de texto são exibidas. Por exemplo, observe que 3 não pode ser representado como um SingleHue valor porque 3 não é o valor subjacente de nenhum SingleHue membro, enquanto o FlagsAttribute atributo torna possível representar 3 como um MultiHue valor de Black, Red.

O exemplo a seguir define outra enumeração com o FlagsAttribute atributo e mostra como usar operadores lógicos e de igualdade bitwise para determinar se um ou mais campos de bit são definidos em um valor de enumeração. Você também pode usar o Enum.HasFlag método para fazer isso, mas isso não é mostrado neste exemplo.

using System;

[Flags]
public enum PhoneService
{
    None = 0,
    LandLine = 1,
    Cell = 2,
    Fax = 4,
    Internet = 8,
    Other = 16
}

public class Example1
{
    public static void Main()
    {
        // Define three variables representing the types of phone service
        // in three households.
        var household1 = PhoneService.LandLine | PhoneService.Cell |
                         PhoneService.Internet;
        var household2 = PhoneService.None;
        var household3 = PhoneService.Cell | PhoneService.Internet;

        // Store the variables in an array for ease of access.
        PhoneService[] households = { household1, household2, household3 };

        // Which households have no service?
        for (int ctr = 0; ctr < households.Length; ctr++)
            Console.WriteLine($"Household {ctr + 1} has phone service:" +
                $"{(households[ctr] == PhoneService.None ? "No" : "Yes")}");
        Console.WriteLine();

        // Which households have cell phone service?
        for (int ctr = 0; ctr < households.Length; ctr++)
            Console.WriteLine($"Household {ctr + 1} has cell phone service: " +
                $"{((households[ctr] & PhoneService.Cell) == PhoneService.Cell ? "Yes" : "No")}");
        Console.WriteLine();

        // Which households have cell phones and land lines?
        var cellAndLand = PhoneService.Cell | PhoneService.LandLine;
        for (int ctr = 0; ctr < households.Length; ctr++)
            Console.WriteLine($"Household {ctr + 1} has cell and land line service: " +
                $"{((households[ctr] & cellAndLand) == cellAndLand ? "Yes" : "No")}");
        Console.WriteLine();

        // List all types of service of each household?//
        for (int ctr = 0; ctr < households.Length; ctr++)
            Console.WriteLine($"Household {ctr + 1} has: {households[ctr]:G}");
        Console.WriteLine();
    }
}
// The example displays the following output:
//    Household 1 has phone service: Yes
//    Household 2 has phone service: No
//    Household 3 has phone service: Yes
//
//    Household 1 has cell phone service: Yes
//    Household 2 has cell phone service: No
//    Household 3 has cell phone service: Yes
//
//    Household 1 has cell and land line service: Yes
//    Household 2 has cell and land line service: No
//    Household 3 has cell and land line service: No
//
//    Household 1 has: LandLine, Cell, Internet
//    Household 2 has: None
//    Household 3 has: Cell, Internet
open System

[<Flags>]
type PhoneService =
    | None = 0
    | LandLine = 1
    | Cell = 2
    | Fax = 4
    | Internet = 8
    | Other = 16

// Define three variables representing the types of phone service
// in three households.
let household1 = 
    PhoneService.LandLine ||| PhoneService.Cell ||| PhoneService.Internet

let household2 = 
    PhoneService.None

let household3 = 
    PhoneService.Cell ||| PhoneService.Internet

// Store the variables in a list for ease of access.
let households =
    [ household1; household2; household3 ]

// Which households have no service?
for i = 0 to households.Length - 1 do
    printfn $"""Household {i + 1} has phone service: {if households[i] = PhoneService.None then "No" else "Yes"}"""
printfn ""

// Which households have cell phone service?
for i = 0 to households.Length - 1 do
    printfn $"""Household {i + 1} has cell phone service: {if households[i] &&& PhoneService.Cell = PhoneService.Cell then "Yes" else "No"}"""
printfn ""

// Which households have cell phones and land lines?
let cellAndLand = 
    PhoneService.Cell ||| PhoneService.LandLine

for i = 0 to households.Length - 1 do
    printfn $"""Household {i + 1} has cell and land line service: {if households[i] &&& cellAndLand = cellAndLand then "Yes" else "No"}"""
printfn ""

// List all types of service of each household?//
for i = 0 to households.Length - 1 do
    printfn $"Household {i + 1} has: {households[i]:G}"

// The example displays the following output:
//    Household 1 has phone service: Yes
//    Household 2 has phone service: No
//    Household 3 has phone service: Yes
//
//    Household 1 has cell phone service: Yes
//    Household 2 has cell phone service: No
//    Household 3 has cell phone service: Yes
//
//    Household 1 has cell and land line service: Yes
//    Household 2 has cell and land line service: No
//    Household 3 has cell and land line service: No
//
//    Household 1 has: LandLine, Cell, Internet
//    Household 2 has: None
//    Household 3 has: Cell, Internet
<Flags()>
Public Enum PhoneService As Integer
   None = 0
   LandLine = 1
   Cell = 2
   Fax = 4
   Internet = 8
   Other = 16
End Enum

Module Example1
   Public Sub Main()
      ' Define three variables representing the types of phone service
      ' in three households.
      Dim household1 As PhoneService = PhoneService.LandLine Or
                                       PhoneService.Cell Or
                                       PhoneService.Internet
      Dim household2 As PhoneService = PhoneService.None
      Dim household3 As PhoneService = PhoneService.Cell Or
                                       PhoneService.Internet

      ' Store the variables in an array for ease of access.
      Dim households() As PhoneService = { household1, household2,
                                           household3 }

      ' Which households have no service?
      For ctr As Integer = 0 To households.Length - 1
         Console.WriteLine("Household {0} has phone service: {1}",
                           ctr + 1,
                           If(households(ctr) = PhoneService.None,
                              "No", "Yes"))
      Next
      Console.WriteLine()
      
      ' Which households have cell phone service?
      For ctr As Integer = 0 To households.Length - 1
         Console.WriteLine("Household {0} has cell phone service: {1}",
                           ctr + 1,
                           If((households(ctr) And PhoneService.Cell) = PhoneService.Cell,
                              "Yes", "No"))
      Next
      Console.WriteLine()
      
      ' Which households have cell phones and land lines?
      Dim cellAndLand As PhoneService = PhoneService.Cell Or PhoneService.LandLine
      For ctr As Integer = 0 To households.Length - 1
         Console.WriteLine("Household {0} has cell and land line service: {1}",
                           ctr + 1,
                           If((households(ctr) And cellAndLand) = cellAndLand,
                              "Yes", "No"))
      Next
      Console.WriteLine()
      
      ' List all types of service of each household?'
      For ctr As Integer = 0 To households.Length - 1
         Console.WriteLine("Household {0} has: {1:G}",
                           ctr + 1, households(ctr))
      Next
      Console.WriteLine()
   End Sub
End Module
' The example displays the following output:
'    Household 1 has phone service: Yes
'    Household 2 has phone service: No
'    Household 3 has phone service: Yes
'
'    Household 1 has cell phone service: Yes
'    Household 2 has cell phone service: No
'    Household 3 has cell phone service: Yes
'
'    Household 1 has cell and land line service: Yes
'    Household 2 has cell and land line service: No
'    Household 3 has cell and land line service: No
'
'    Household 1 has: LandLine, Cell, Internet
'    Household 2 has: None
'    Household 3 has: Cell, Internet