System.FlagsAttribute-klass

Anmärkning

Den här artikeln innehåller ytterligare kommentarer till referensdokumentationen för det här API:et.

Attributet FlagsAttribute anger att en uppräkning kan behandlas som ett bitfält, dvs. en uppsättning flaggor.

Bitfält används vanligtvis för listor över element som kan förekomma i kombination, medan uppräkningskonstanter vanligtvis används för listor över ömsesidigt uteslutande element. Därför är bitfält utformade för att kombineras med en bitvis OR åtgärd för att generera namnlösa värden, medan uppräknade konstanter inte är det. Språken varierar i användningen av bitfält jämfört med uppräkningskonstanter.

Attribut för FlagsAttribute

AttributeUsageAttribute tillämpas på den här klassen och dess Inherited egenskap anger false. Det här attributet kan bara användas för uppräkningar.

Riktlinjer för FlagsAttribute och enum

  • Använd det FlagsAttribute anpassade attributet för en uppräkning endast om en bitvis åtgärd (AND, OR, EXCLUSIVE OR) ska utföras på ett numeriskt värde.

  • Definiera uppräkningskonstanter i två krafter, dvs. 1, 2, 4, 8 och så vidare. Det innebär att de enskilda flaggorna i kombinerade uppräkningskonstanter inte överlappar varandra.

  • Överväg att skapa en uppräknad konstant för vanliga flaggkombinationer. Om du till exempel har en uppräkning som används för fil-I/O-åtgärder som innehåller de uppräknade konstanterna Read = 1 och Write = 2kan du skapa den uppräknade konstanten ReadWrite = Read OR Write, som kombinerar flaggorna Read och Write. Dessutom kan den bitvis OR-åtgärd som används för att kombinera flaggorna betraktas som ett avancerat begrepp under vissa omständigheter som inte bör krävas för enkla uppgifter.

  • Var försiktig om du definierar ett negativt tal som en flagga uppräknad konstant eftersom många flaggpositioner kan vara inställda på 1, vilket kan göra koden förvirrande och uppmuntra kodfel.

  • Ett bekvämt sätt att testa om en flagga anges i ett numeriskt värde är att utföra en bitvis AND-åtgärd mellan det numeriska värdet och den flagga uppräknade konstanten, som anger alla bitar i det numeriska värdet till noll som inte motsvarar flaggan, och sedan testa om resultatet av åtgärden är lika med den uppräknade flaggans konstant.

  • Använd None som namnet på den uppräknade flaggans konstant vars värde är noll. Du kan inte använda den None uppräknade konstanten i en bitvis AND-åtgärd för att testa för en flagga eftersom resultatet alltid är noll. Du kan dock utföra en logisk jämförelse, inte en bitvis, mellan det numeriska värdet och den None uppräknade konstanten för att avgöra om några bitar i det numeriska värdet har angetts.

    Om du skapar en värdeuppräkning i stället för en uppräkning av flaggor är det fortfarande värt att skapa en None uppräknad konstant. Anledningen är att det minne som används för uppräkningen initieras som standard till noll av Common Language Runtime. Om du inte definierar en konstant vars värde är noll kommer uppräkningen därför att innehålla ett ogiltigt värde när det skapas.

    Om det finns ett uppenbart standardfall som ditt program måste representera kan du överväga att använda en uppräknad konstant vars värde är noll för att representera standardvärdet. Om det inte finns något standardfall bör du överväga att använda en uppräknad konstant vars värde är noll, vilket innebär att det fall som inte representeras av någon av de andra uppräknade konstanterna.

  • Definiera inte ett uppräkningsvärde enbart för att spegla uppräkningstillståndet. Definiera till exempel inte en uppräknad konstant som bara markerar slutet på uppräkningen. Om du behöver fastställa det sista värdet för uppräkningen kontrollerar du uttryckligen det värdet. Dessutom kan du utföra en intervallkontroll för den första och sista uppräknade konstanten om alla värden inom intervallet är giltiga.

  • Ange inte uppräknade konstanter som är reserverade för framtida användning.

  • När du definierar en metod eller egenskap som tar en uppräknad konstant som ett värde bör du överväga att validera värdet. Anledningen är att du kan omvandla ett numeriskt värde till uppräkningstypen även om det numeriska värdet inte har definierats i uppräkningen.

Exempel

Följande exempel illustrerar användningen av FlagsAttribute attributet och visar effekten på ToString metoden för att använda FlagsAttribute på en Enum deklaration.

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

I föregående exempel definieras två färgrelaterade uppräkningar, SingleHue och MultiHue. Det senare har FlagsAttribute attributet, det förra har det inte. Exemplet visar skillnaden i beteende när ett antal heltal, inklusive heltal som inte representerar underliggande värden av uppräkningstypen, omvandlas till uppräkningstypen och deras strängrepresentationer visas. Observera till exempel att 3 inte kan representeras som ett SingleHue värde eftersom 3 inte är det underliggande värdet för någon SingleHue medlem, medan FlagsAttribute attributet gör det möjligt att representera 3 som ett MultiHue värde av Black, Red.

I följande exempel definieras en annan uppräkning med FlagsAttribute attributet och visar hur du använder bitvis logiska operatorer och likhetsoperatorer för att avgöra om ett eller flera bitfält anges i ett uppräkningsvärde. Du kan också använda Enum.HasFlag metoden för att göra det, men det visas inte i det här exemplet.

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