列挙型 (Enumerated type)

構文

enum MyEnum { A, B, C }

CLRでは、すべての列挙型はSystem.Enumから派生したクラスです。Enum メンバ (System) | MSDN

基礎となる型

すべての列挙型には基礎となる型があり、これは

enum MyEnum : byte {}

のように列挙型の定義時に指定できます。これに指定できる型は下表に示す単純型のみで、省略した場合にはintが採用されます。

符号あり 符号なし
sbyte byte
short ushort
int uint
long ulong

すでに定義されている列挙型の型は、EnumクラスのGetUnderlyingType()メソッドで取得できます。

ビットフラグ

すべての識別子にビットに対応する値を設定することで、列挙型をビットフラグとして利用できます。これはSystem.FlagsAttribute属性として指定することで定義でき、たとえばFileAttributesでは次のように用いられています。

[Serializable]
[Flags]
[System.Runtime.InteropServices.ComVisible(true)]
public enum FileAttributes
{
    // From WinNT.h (FILE_ATTRIBUTE_XXX)
    ReadOnly = 0x1,
    Hidden = 0x2,
    System = 0x4,
    ︙
FileAttributes - fileattributes.cs

このように定義された列挙型は、次のように利用できます。

// 複数のフラグを設定する
FileAttributes a = FileAttributes.ReadOnly | FileAttributes.Hidden;

// フラグの有無を確認する
if ((a & FileAttributes.Hidden) == FileAttributes.Hidden)
{
}

なお.NET Framework 4.0以降ならば、フラグの有無はHasFlag()でも確認できます。Enum.HasFlag(Enum) メソッド (System) | Microsoft Learn

if (a.HasFlag(FileAttributes.Hidden))
{
    // Hiddenがある
}
if (a.HasFlag(FileAttributes.ReadOnly | FileAttributes.Hidden))
{
    // ReadOnlytとHiddenがある
}
if (a.HasFlag(FileAttributes.ReadOnly) || a.HasFlag(FileAttributes.Hidden))
{
    // ReadOnlytまたはHiddenがある
}

// 次のようにも記述できる
if ((a & (FileAttributes.ReadOnly | FileAttributes.Hidden)) != 0)
{
}

このメソッドはFlagsAttributeが付けられた列挙型のビットフィールドを判定するためのものであり、この属性がなければEquals()またはCompareTo()を呼びます。

Flags属性を付けるだけで2の累乗の値が設定されるわけではなく、値を明示しなければビットフラグとして使用できません。What does the [Flags] Enum Attribute mean in C#? - Stack Overflow

[Flags]
enum MyEnum { A, B, C, D }
int a1 = (int)MyEnum.A; // 0
int a2 = (int)MyEnum.B; // 1
int a3 = (int)MyEnum.C; // 2
int a4 = (int)MyEnum.D; // 3

MyEnum myEnum = MyEnum.A | MyEnum.B; // B

Flags属性を付けているのにその要件を満たしていないと、「'A1' は FlagsAttribute に設定されていますが、列挙値の範囲で使用される設定可能な各ビットに対して、個別のメンバーが見つかりません。型から FlagsAttribute を削除するか、または現在存在していない次の値に対して新しいメンバーを定義してください: 0x2」としてCA2217で警告されます。

[Flags]
public enum A1
{
    A = 0, B = 1, C = 3, D = 4
}

一方で要件を満たしているのにFlags属性を付けていないと「'A2' の構成メンバーは、個別の値ではなく、組み合わせ可能なフラグを示しています。この情報が正しい場合、列挙を FlagsAttribute に設定してください。」としてCA1027で警告されます。

public enum A2
{
    A = 0, B = 1, C = 2, D = 4
}

型の変換

基礎となる型との変換

enum MyEnum1 { A, B, C }
enum MyEnum2 { A, B = 20, C }

public class MyClass
{
    public void Method()
    {
        // 列挙型から、基礎となる型への変換
        int a1 = (int)MyEnum1.A; // 0
        int a2 = (int)MyEnum1.B; // 1
        int a3 = (int)MyEnum1.C; // 2

        int a4 = (int)MyEnum2.A; // 0
        int a5 = (int)MyEnum2.B; // 20
        int a6 = (int)MyEnum2.C; // 21

        // 基礎となる型から、列挙型への変換
        MyEnum1 e1 = (MyEnum1)1; // B
        MyEnum1 e2 = (MyEnum1)3; // 3 (未定義の値)

        MyEnum1 e3 = (MyEnum1)Enum.ToObject(typeof(MyEnum1), 1); // B
        MyEnum1 e4 = (MyEnum1)Enum.ToObject(typeof(MyEnum1), 3); // 3 (未定義の値)
    }
}
変換の実行 - Enum クラス (System) | Microsoft Learn

未定義の値でも列挙型へキャストできるため、予期せぬ値になることがあります。それが問題となるときには、IsDefined()で確認します。Enum.IsDefined メソッド (System) | Microsoft Learn

bool b1 = Enum.IsDefined(typeof(MyEnum1), 1); // true
bool b2 = Enum.IsDefined(typeof(MyEnum1), 3); // false

文字列との変換

列挙型から文字列への変換

enum MyEnum1 { A, B, C }
enum MyEnum2 { A, B = 20, C }

public class MyClass
{
    public void Method()
    {
        string str1 = MyEnum1.B.ToString(); // B
        string str2 = MyEnum2.B.ToString(); // B
    }
}

文字列から列挙型への変換

列挙値の解析 - Enum クラス (System) | MSDN

[ComVisibleAttribute(true)]
public static object Parse(
    Type enumType,
    string value
)
Enum.Parse メソッド (Type, String) (System) | MSDN

このメソッドでは大文字/小文字が区別されて評価されます。その区別が不要ならば、次のメソッドでignoreCaseをtrueとします。

[ComVisibleAttribute(true)]
public static object Parse(
    Type enumType,
    string value,
    bool ignoreCase
)
Enum.Parse メソッド (Type, String, Boolean) (System) | MSDN
enum MyEnum { A, B, C }

public class MyClass
{
    public void Method()
    {
        MyEnum myEnumB = (MyEnum)Enum.Parse(typeof(MyEnum), "B"); // B
        MyEnum myEnumD = (MyEnum)Enum.Parse(typeof(MyEnum), "D"); // System.ArgumentException 要求された値 'D' が見つかりませんでした。
    }
}

Parse()では、指定の文字列に一致する値が存在しないときには例外が発生します。これを戻り値で結果を知るには、次のTryParse()を用います。

public static bool TryParse<TEnum>(
    string value,
    out TEnum result
)
where TEnum : struct
Enum.TryParse(TEnum) メソッド (String, TEnum) (System) | MSDN
enum MyEnum { A, B, C }

public class MyClass
{
    public void Method()
    {
        MyEnum myEnum;
        if (Enum.TryParse<MyEnum>("B", out myEnum))
        {
        }
        // myEnumは"B"となる

        if (Enum.TryParse<MyEnum>("D", out myEnum))
        {
        }
        // myEnumは既定値の"A"となる
    }
}

演算子

以下の演算子がサポートされます。18.6 Enum values and operations - Enums - C# language specification | Microsoft Learn

  • ==, !=, <, >, <=, >=
  • binary +
  • binary -
  • ^, &, |
  • ~
  • ++, --
  • sizeof
enum MyEnum { A, B }


MyEnum a = MyEnum.A;
a.ToString(); // "A"

a++;
a.ToString(); // "B"

a++;
a.ToString(); // "2"

列挙型のメンバーの反復

GetNames()で列挙型のすべての名前を、GetValues()ですべての値を得られます。

Array values = Enum.GetValues(typeof(MyEnum));
foreach (object value in values)
{
    string name = value.ToString();
    int number = (int)value;
}
列挙メンバーの反復処理 - Enum クラス (System) | Microsoft Learn
Microsoft Learnから検索