System.FlagsAttribute-Klasse
Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.
Das FlagsAttribute Attribut gibt an, dass eine Aufzählung als Bitfeld behandelt werden kann, d. h. eine Reihe von Flags.
Bitfelder werden in der Regel für Listen von Elementen verwendet, die in Kombination auftreten können, während Enumerationskonstanten in der Regel für Listen sich gegenseitig ausschließenden Elemente verwendet werden. Daher sind Bitfelder so konzipiert, dass sie mit einem bitweisen OR
Vorgang kombiniert werden, um unbenannte Werte zu generieren, während aufgezählte Konstanten nicht vorhanden sind. Sprachen unterscheiden sich bei der Verwendung von Bitfeldern im Vergleich zu Enumerationskonstanten.
Attribute des FlagsAttributes
AttributeUsageAttribute wird auf diese Klasse angewendet, und seine Inherited Eigenschaft gibt an false
. Dieses Attribut kann nur auf Enumerationen angewendet werden.
Richtlinien für FlagsAttribute und Enumeration
Verwenden Sie das FlagsAttribute benutzerdefinierte Attribut nur für eine Enumeration, wenn ein bitweiser Vorgang (AND, OR, EXCLUSIVE OR) für einen numerischen Wert ausgeführt werden soll.
Definieren Sie Enumerationskonstanten in Potenzen von zwei, d. h. 1, 2, 4, 8 usw. Dies bedeutet, dass die einzelnen Flags in kombinierten Enumerationskonstanten nicht überlappen.
Erwägen Sie das Erstellen einer aufgezählten Konstante für häufig verwendete Flagkombinationen. Wenn Sie z. B. eine Aufzählung für Datei-E/A-Vorgänge verwenden, die die aufgezählten Konstanten
Read = 1
enthalten, undWrite = 2
erwägen Sie, die aufgezählte Konstante zu erstellen, die dieRead
enumerierten KonstantenReadWrite = Read OR Write
kombiniert undWrite
flags kombiniert. Darüber hinaus kann der bitweise ODER-Vorgang, der zum Kombinieren der Flags verwendet wird, unter bestimmten Umständen als ein erweitertes Konzept angesehen werden, das nicht für einfache Aufgaben erforderlich sein sollte.Verwenden Sie Vorsicht, wenn Sie eine negative Zahl als aufgezählte Kennzeichnungskonstante definieren, da viele Flagpositionen möglicherweise auf 1 festgelegt werden, was dazu führen kann, dass Der Code verwirrend ist und Codierungsfehler animiert.
Eine bequeme Möglichkeit, zu testen, ob ein Flag in einem numerischen Wert festgelegt ist, besteht darin, einen bitweisen AND-Vorgang zwischen dem numerischen Wert und der Flag-Aufzählungskonstante auszuführen, die alle Bits im numerischen Wert auf Null festlegt, die nicht dem Flag entsprechen, und dann testen Sie, ob das Ergebnis dieses Vorgangs der Flag-Aufzählungskonstante entspricht.
Wird als Name der aufgezählten Flagkonstante verwendet
None
, deren Wert null ist. Sie können dieNone
aufgezählte Konstante in einem bitweisen AND-Vorgang nicht verwenden, um eine Kennzeichnung zu testen, da das Ergebnis immer null ist. Sie können jedoch einen logischen, nicht bitweisen Vergleich zwischen dem numerischen Wert und derNone
aufgezählten Konstante durchführen, um zu bestimmen, ob Bits im numerischen Wert festgelegt werden.Wenn Sie eine Wertaufzählung anstelle einer Flags-Aufzählung erstellen, lohnt es sich dennoch, eine
None
aufgezählte Konstante zu erstellen. Der Grund dafür ist, dass der für die Enumeration verwendete Arbeitsspeicher standardmäßig von der Common Language Runtime auf Null initialisiert wird. Wenn Sie also keine Konstante definieren, deren Wert null ist, enthält die Aufzählung beim Erstellen einen unzulässigen Wert.Wenn es einen offensichtlichen Standardfall gibt, den Ihre Anwendung darstellen muss, sollten Sie eine aufgezählte Konstante verwenden, deren Wert null ist, um den Standardwert darzustellen. Wenn kein Standardfall vorhanden ist, sollten Sie eine Aufzählungskonstante verwenden, deren Wert null ist, d. h. den Fall, der nicht durch eine der anderen aufgezählten Konstanten dargestellt wird.
Definieren Sie keinen Enumerationswert nur, um den Zustand der Enumeration selbst zu Spiegel. Definieren Sie beispielsweise keine aufgezählte Konstante, die lediglich das Ende der Enumeration kennzeichnet. Wenn Sie den letzten Wert der Aufzählung ermitteln müssen, überprüfen Sie explizit auf diesen Wert. Darüber hinaus können Sie eine Bereichsprüfung für die erste und letzte aufgezählte Konstante ausführen, wenn alle Werte innerhalb des Bereichs gültig sind.
Geben Sie keine aufgezählten Konstanten an, die für die zukünftige Verwendung reserviert sind.
Wenn Sie eine Methode oder Eigenschaft definieren, die eine aufgezählte Konstante als Wert verwendet, sollten Sie die Überprüfung des Werts in Betracht ziehen. Der Grund dafür ist, dass Sie einen numerischen Wert in den Enumerationstyp umwandeln können, auch wenn dieser numerische Wert nicht in der Enumeration definiert ist.
Beispiele
Das folgende Beispiel veranschaulicht die Verwendung des FlagsAttribute
Attributs und zeigt den Effekt auf die ToString Verwendungsmethode FlagsAttribute
für eine 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
Im vorherigen Beispiel werden zwei farbbezogene Enumerationen SingleHue
und MultiHue
. Letzteres weist das FlagsAttribute
Attribut auf; das frühere Attribut ist nicht vorhanden. Das Beispiel zeigt den Unterschied im Verhalten, wenn ein Ganzzahlbereich, einschließlich ganzzahliger Zahlen, die keine zugrunde liegenden Werte des Enumerationstyps darstellen, in den Enumerationstyp umgewandelt werden und deren Zeichenfolgendarstellungen angezeigt werden. Beachten Sie beispielsweise, dass 3 nicht als SingleHue
Wert dargestellt werden kann, da 3 nicht der zugrunde liegende Wert eines Elements SingleHue
ist, während das FlagsAttribute
Attribut die Darstellung von 3 als MultiHue
Wert ermöglicht Black, Red
.
Im folgenden Beispiel wird eine weitere Aufzählung mit dem FlagsAttribute
Attribut definiert und veranschaulicht, wie Sie mit bitweisen logischen Operatoren und Gleichheitsoperatoren bestimmen können, ob ein oder mehrere Bitfelder in einem Enumerationswert festgelegt werden. Sie können dies auch mit der Enum.HasFlag Methode tun, aber dies wird in diesem Beispiel nicht gezeigt.
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