この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。
FlagsAttribute 属性は、列挙型をビット フィールドとして扱うことができることを示します。つまり、フラグのセットです。
ビット フィールドは、一般的に組み合わせて発生する可能性がある要素のリストに使用されますが、列挙定数は、一般的に相互に排他的な要素のリストに使用されます。 したがって、ビット フィールドはビットごとの OR
演算と組み合わせて名前のない値を生成するように設計されていますが、列挙定数は生成されません。 言語は、列挙定数と比較してビット フィールドの使用によって異なります。
FlagsAttribute の属性
AttributeUsageAttribute はこのクラスに適用され、その Inherited プロパティは false
を指定します。 この属性は、列挙型にのみ適用できます。
FlagsAttribute と enum のためのガイドライン
FlagsAttribute カスタム属性は、ビットごとの演算 (AND、OR、EXCLUSIVE OR) が数値に対して実行される場合にのみ使用します。
2 の累乗 (1、2、4、8 など) で列挙定数を定義します。 これは、結合された列挙定数内の個々のフラグが重複しないことを意味します。
一般的に使用されるフラグの組み合わせに対して列挙定数を作成することを検討してください。 たとえば、列挙定数
Read = 1
およびWrite = 2
を含むファイル I/O 操作に使用される列挙体がある場合は、ReadWrite = Read OR Write
フラグとRead
フラグを組み合わせた列挙定数Write
を作成することを検討してください。 さらに、フラグの結合に使用されるビットごとの OR 演算は、単純なタスクでは必要ない状況では高度な概念と見なされる場合があります。フラグの位置が 1 に設定されている可能性があるため、負の数をフラグ列挙定数として定義する場合は注意が必要です。そのため、コードが混乱し、コーディング エラーが発生する可能性があります。
フラグが数値に設定されているかどうかをテストする便利な方法は、数値とフラグ列挙定数の間でビットごとの AND 演算を実行することです。この定数では、数値内のすべてのビットがフラグに対応しない 0 に設定され、その操作の結果がフラグ列挙定数と等しいかどうかをテストします。
値が 0 のフラグ列挙定数の名前として
None
を使用します。 結果は常に 0 であるため、None
列挙定数をビットごとの AND 演算で使用してフラグをテストすることはできません。 ただし、数値とNone
列挙定数の論理比較を実行して、数値内のビットが設定されているかどうかを判断できます。フラグ列挙の代わりに値列挙を作成する場合でも、
None
列挙定数を作成する価値があります。 その理由は、既定では、列挙型に使用されるメモリが共通言語ランタイムによって 0 に初期化されるためです。 したがって、値が 0 の定数を定義しない場合、列挙型の作成時に無効な値が含まれます。アプリケーションで表す必要がある明らかな既定のケースがある場合は、既定値を表す値が 0 の列挙定数の使用を検討してください。 既定のケースがない場合は、値が 0 の列挙定数を使用することを検討してください。これは、他のどの列挙定数でも表されないケースを意味します。
列挙値は、列挙体自体の状態をミラーリングするためだけに定義しないでください。 たとえば、列挙体の末尾だけをマークする列挙定数を定義しないでください。 列挙体の最後の値を確認する必要がある場合は、その値を明示的に確認します。 また、範囲内のすべての値が有効な場合は、最初と最後の列挙定数の範囲チェックを実行できます。
将来使用するために予約されている列挙定数は指定しないでください。
列挙定数を値として受け取るメソッドまたはプロパティを定義する場合は、値の検証を検討してください。 その理由は、その数値が列挙型で定義されていない場合でも、数値を列挙型にキャストできるためです。
例示
次の例は、FlagsAttribute
属性の使用を示し、ToString 宣言で FlagsAttribute
を使用する Enum メソッドへの影響を示しています。
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
前の例では、SingleHue
と MultiHue
の 2 つの色関連列挙型を定義しています。 後者には FlagsAttribute
属性があります。前者はしません。 この例では、列挙型の基になる値を表さない整数を含む整数の範囲が列挙型にキャストされ、その文字列表現が表示される場合の動作の違いを示します。 たとえば、3 は SingleHue
メンバーの基になる値ではないため、3 は SingleHue
値として表すことはできませんが、FlagsAttribute
属性では、MultiHue
の Black, Red
値として 3 を表すことができます。
次の例では、FlagsAttribute
属性を持つ別の列挙体を定義し、ビットごとの論理演算子と等値演算子を使用して、列挙値に 1 つ以上のビット フィールドが設定されているかどうかを判断する方法を示します。
Enum.HasFlag メソッドを使用してこれを行うこともできますが、この例では示されていません。
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
.NET