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 etWrite = 2
, envisagez de créer la constanteReadWrite = Read OR Write
énumérée, qui combine les indicateurs etWrite
lesRead
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 laNone
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 laNone
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 SingleHue
MultiHue
. 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