Classe System.FlagsAttribute

Cet article vous offre des remarques complémentaires à la documentation de référence pour cette API.

L’attribut FlagsAttribute indique qu’une énumération peut être traitée comme un champ de bits ; autrement dit, un ensemble d’indicateurs.

Les champs de bits sont généralement utilisés pour les listes d’éléments qui peuvent se produire en combinaison, tandis que les constantes d’énumération sont généralement utilisées pour les listes d’éléments mutuellement exclusifs. Par conséquent, les champs de bits sont conçus pour être combinés avec une opération au niveau OR du bit pour générer des valeurs non nommées, tandis que les constantes énumérées ne sont pas. Les langues varient en fonction de leur utilisation de champs de bits par rapport aux constantes d’énumération.

Attributs de FlagsAttribute

AttributeUsageAttribute est appliqué à cette classe, et sa Inherited propriété spécifie false. Cet attribut ne peut être appliqué qu’aux énumérations.

Instructions pour FlagsAttribute et enum

  • Utilisez l’attribut FlagsAttribute personnalisé pour une énumération uniquement si une opération au niveau du bit (AND, OR, EXCLUSIVE OR) doit être effectuée sur une valeur numérique.

  • Définissez les constantes d’énumération en puissances de deux, autrement dit, 1, 2, 4, 8, et ainsi de suite. Cela signifie que les indicateurs individuels dans les constantes d’énumération combinées ne se chevauchent pas.

  • Envisagez de créer une constante énumérée pour les combinaisons d’indicateurs couramment utilisées. Par exemple, si vous avez une énumération utilisée pour les opérations d’E/S de fichier qui contient les constantes Read = 1 énumérées et Write = 2, envisagez de créer la constante ReadWrite = Read OR Writeénumérée, qui combine les indicateurs et Write les Read indicateurs. En outre, l’opération OR au niveau du bit utilisée pour combiner les indicateurs peut être considérée comme un concept avancé dans certaines circonstances qui ne doivent pas être nécessaires pour des tâches simples.

  • Soyez prudent si vous définissez un nombre négatif comme constante énumérée d’indicateurs, car de nombreuses positions d’indicateur peuvent être définies sur 1, ce qui peut rendre votre code déroutant et encourager les erreurs de codage.

  • Un moyen pratique de tester si un indicateur est défini dans une valeur numérique consiste à effectuer une opération AND au niveau du bit entre la valeur numérique et la constante énumérée de l’indicateur, qui définit tous les bits de la valeur numérique sur zéro qui ne correspondent pas à l’indicateur, puis testez si le résultat de cette opération est égal à la constante énumérée de l’indicateur.

  • Utilisez None le nom de la constante énumérée de l’indicateur dont la valeur est égale à zéro. Vous ne pouvez pas utiliser la None constante énumérée dans une opération AND au niveau du bit pour tester un indicateur, car le résultat est toujours égal à zéro. Toutefois, vous pouvez effectuer une comparaison logique, et non pas au niveau du bit, entre la valeur numérique et la None constante énumérée pour déterminer si les bits de la valeur numérique sont définis.

    Si vous créez une énumération de valeur au lieu d’une énumération d’indicateurs, il vaut toujours la peine de créer une None constante énumérée. La raison est que par défaut, la mémoire utilisée pour l’énumération est initialisée à zéro par le Common Language Runtime. Par conséquent, si vous ne définissez pas de constante dont la valeur est égale à zéro, l’énumération contient une valeur illégale lors de sa création.

    S’il existe un cas par défaut évident que votre application doit représenter, envisagez d’utiliser une constante énumérée dont la valeur est égale à zéro pour représenter la valeur par défaut. S’il n’existe aucun cas par défaut, envisagez d’utiliser une constante énumérée dont la valeur est égale à zéro, ce qui signifie que le cas qui n’est représenté par aucune des autres constantes énumérées.

  • Ne définissez pas une valeur d’énumération uniquement pour miroir l’état de l’énumération proprement dite. Par exemple, ne définissez pas de constante énumérée qui marque simplement la fin de l’énumération. Si vous devez déterminer la dernière valeur de l’énumération, case activée pour cette valeur explicitement. En outre, vous pouvez effectuer une plage case activée pour la première et la dernière constante énumérée si toutes les valeurs de la plage sont valides.

  • Ne spécifiez pas de constantes énumérées réservées pour une utilisation ultérieure.

  • Lorsque vous définissez une méthode ou une propriété qui prend une constante énumérée comme valeur, envisagez de valider la valeur. La raison est que vous pouvez convertir une valeur numérique en type d’énumération même si cette valeur numérique n’est pas définie dans l’énumération.

Exemples

L’exemple suivant illustre l’utilisation de l’attribut FlagsAttribute et montre l’effet sur la ToString méthode d’utilisation FlagsAttribute sur une Enum déclaration.

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

L’exemple précédent définit deux énumérations liées aux couleurs et SingleHueMultiHue. Ce dernier a l’attribut FlagsAttribute ; l’ancien ne le fait pas. L’exemple montre la différence de comportement lorsqu’une plage d’entiers, y compris des entiers qui ne représentent pas les valeurs sous-jacentes du type d’énumération, sont convertis en type d’énumération et leurs représentations sous-jacentes affichées. Par exemple, notez que 3 ne peut pas être représenté en tant que SingleHue valeur, car 3 n’est pas la valeur sous-jacente d’un SingleHue membre, tandis que l’attribut FlagsAttribute permet de représenter 3 comme MultiHue valeur de Black, Red.

L’exemple suivant définit une autre énumération avec l’attribut FlagsAttribute et montre comment utiliser des opérateurs logiques et d’égalité au niveau du bit pour déterminer si un ou plusieurs champs de bits sont définis dans une valeur d’énumération. Vous pouvez également utiliser la Enum.HasFlag méthode pour ce faire, mais cela n’est pas illustré dans cet exemple.

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 {0} has phone service: {1}",
                              ctr + 1,
                              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 {0} has cell phone service: {1}",
                              ctr + 1,
                              (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 {0} has cell and land line service: {1}",
                              ctr + 1,
                              (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 {0} has: {1:G}",
                              ctr + 1, households[ctr]);
        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