Classe System.FlagsAttribute

Questo articolo fornisce osservazioni supplementari alla documentazione di riferimento per questa API.

L'attributo FlagsAttribute indica che un'enumerazione può essere considerata come un campo di bit, ovvero un set di flag.

I campi di bit vengono in genere utilizzati per elenchi di elementi che possono verificarsi in combinazione, mentre le costanti di enumerazione vengono in genere utilizzate per elenchi di elementi che si escludono a vicenda. Pertanto, i campi di bit sono progettati per essere combinati con un'operazione bit per OR bit per generare valori senza nome, mentre le costanti enumerate non sono. I linguaggi variano nell'uso dei campi di bit rispetto alle costanti di enumerazione.

Attributi di FlagsAttribute

AttributeUsageAttribute viene applicato a questa classe e la relativa Inherited proprietà specifica false. Questo attributo può essere applicato solo alle enumerazioni.

Linee guida per FlagsAttribute ed enumerazione

  • Usare l'attributo personalizzato per un'enumerazione FlagsAttribute solo se un'operazione bit per bit (AND, OR, EXCLUSIVE OR) deve essere eseguita su un valore numerico.

  • Definire le costanti di enumerazione nelle potenze di due, ovvero 1, 2, 4, 8 e così via. Ciò significa che i singoli flag nelle costanti di enumerazione combinata non si sovrappongono.

  • Prendere in considerazione la creazione di una costante enumerata per le combinazioni di flag di uso comune. Ad esempio, se si dispone di un'enumerazione usata per le operazioni di I/O di file che contiene le costanti Read = 1 enumerate e Write = 2, è consigliabile creare la costante ReadWrite = Read OR Writeenumerata , che combina i Read flag e Write . Inoltre, l'operazione OR bit per bit usata per combinare i flag potrebbe essere considerata un concetto avanzato in alcune circostanze che non devono essere necessarie per attività semplici.

  • Prestare attenzione se si definisce un numero negativo come costante enumerata di flag perché molte posizioni dei flag potrebbero essere impostate su 1, che potrebbero generare confusione nel codice e incoraggiare gli errori di codifica.

  • Un modo pratico per verificare se un flag è impostato in un valore numerico consiste nell'eseguire un'operazione AND bit per bit tra il valore numerico e la costante enumerata del flag, che imposta tutti i bit nel valore numerico su zero che non corrispondono al flag, quindi verificare se il risultato di tale operazione è uguale alla costante enumerata del flag.

  • Usare None come nome della costante enumerata flag il cui valore è zero. Non è possibile utilizzare la None costante enumerata in un'operazione AND bit per bit per testare un flag perché il risultato è sempre zero. Tuttavia, è possibile eseguire un confronto logico, non bit per bit, tra il valore numerico e la None costante enumerata per determinare se vengono impostati bit nel valore numerico.

    Se si crea un'enumerazione valore anziché un'enumerazione flag, è comunque utile creare una None costante enumerata. Il motivo è che per impostazione predefinita la memoria usata per l'enumerazione viene inizializzata su zero da Common Language Runtime. Di conseguenza, se non si definisce una costante il cui valore è zero, l'enumerazione conterrà un valore non valido al momento della creazione.

    Se esiste un caso predefinito ovvio che l'applicazione deve rappresentare, è consigliabile usare una costante enumerata il cui valore è zero per rappresentare l'impostazione predefinita. Se non esiste un caso predefinito, è consigliabile utilizzare una costante enumerata il cui valore è zero, ovvero il caso che non è rappresentato da nessuna delle altre costanti enumerate.

  • Non definire un valore di enumerazione esclusivamente per eseguire il mirroring dello stato dell'enumerazione stessa. Ad esempio, non definire una costante enumerata che contrassegna semplicemente la fine dell'enumerazione. Se è necessario determinare l'ultimo valore dell'enumerazione, verificare la presenza di tale valore in modo esplicito. Inoltre, è possibile eseguire un controllo di intervallo per la prima e l'ultima costante enumerata se tutti i valori all'interno dell'intervallo sono validi.

  • Non specificare costanti enumerate riservate per uso futuro.

  • Quando si definisce un metodo o una proprietà che accetta una costante enumerata come valore, è consigliabile convalidare il valore. Il motivo è che è possibile eseguire il cast di un valore numerico al tipo di enumerazione anche se tale valore numerico non è definito nell'enumerazione .

Esempi

Nell'esempio seguente viene illustrato l'uso dell'attributo FlagsAttribute e viene illustrato l'effetto sul ToString metodo di utilizzo FlagsAttribute in una Enum dichiarazione.

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

Nell'esempio precedente vengono definite due enumerazioni correlate al colore e SingleHueMultiHue. Quest'ultimo ha l'attributo FlagsAttribute ; il primo non lo è. L'esempio mostra la differenza di comportamento quando viene eseguito il cast di un intervallo di interi, inclusi i numeri interi che non rappresentano i valori sottostanti del tipo di enumerazione, e le relative rappresentazioni di stringa visualizzate. Si noti, ad esempio, che 3 non può essere rappresentato come SingleHue valore perché 3 non è il valore sottostante di alcun SingleHue membro, mentre l'attributo FlagsAttribute consente di rappresentare 3 come MultiHue valore di Black, Red.

Nell'esempio seguente viene definita un'altra enumerazione con l'attributo FlagsAttribute e viene illustrato come usare operatori logici e di uguaglianza bit per bit per determinare se uno o più campi di bit vengono impostati in un valore di enumerazione. È anche possibile usare il Enum.HasFlag metodo per eseguire questa operazione, ma questo non è illustrato in questo esempio.

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