C# の enum 型
C# の enum 型とは
C# の enum 型は基本的に数値に別名を付けただけのものです。 しかし enum 型を上手に使うと、複数のフラグやスイッチを簡潔に整理することができます。
C# の enum を使って定数を整理する例
例として、方向を表す定数 North、 South、 East、 West を定義して、それらを Move() という関数に渡すことを考えてみましょう。
using System;
class Program
{
const int North = 1;
const int South = 2;
const int East = 3;
const int West = 4;
static void Main(string[] args)
{
Move(South);
}
static void Move(int direction)
{
// ...
}
}
5行目から8行目で定数を定義し、15行目から定義している Move() 関数では int 型の値を受け取ることを期待しています。 確かに 12行目で South を渡して関数を呼び出しています。
しかし、この方法では Move() 関数には int 型の値をなんでも渡すことができるので、 関数側では入力値のチェックも必須になります。また、呼び出すときもどの方向のためにどの値を渡すのか明確ではありません。
そこで enum を使って、このコードがどのように書き換えられるかみてみましょう。
using System;
class Program
{
enum Direction
{
North,
South,
East,
West
}
static void Main(string[] args)
{
Move(Direction.South);
}
static void Move(Direction direction)
{
// ...
}
}
5行目から11行目で Direction という名前の enum 型を定義しています。
18行目で Move() 関数は Direction 型の引数をとることを期待しています。関数の呼び出し側 (15行目) では Direction.South として値を渡しています。
この方法であれば、 Move() 関数はここで定義した enum の Direction で定義した4種類の値しか受け取ることはないので、 想定外の数値が渡されることを考える必要はなくなります。
また、渡す型が明確なので多くのエディタでは入力支援が利用でき、 Direction の種類として 4 種類しかないことも直ちにわかります。
このように enum を使うことで、よりわかりやすいコードを書くことができるようになります。
C# の enum の名前を文字列で取得する
enum に定義された名前は、 ToString() メソッドで文字列として取得することも可能です。
var a = Direction.North;
Console.WriteLine($"{a.ToString()}"); // North
フォーマット文字列の $"{a.ToString()}" は $"{a:G}" としても同様です。
enum 型から全ての名前を取得するには、 Enum.GetNames() を使います。
var names = Enum.GetNames(typeof(Direction));
foreach (var name in names)
{
Console.WriteLine($"{name}");
}
// North
// South
// East
// West
C# の enum でビット演算によるフラグ管理を行う
ビット演算によるフラグ管理を行う場合には、下の例のように 0, 1, 2, 4, ・・・のように 2 の累乗数を明示的に指定します。
[Flags]
enum Direction
{
None = 0,
North = 1,
South = 2,
East = 4,
West = 8
}
すると、enum 値の組み合わせによるフラグを扱えます。
この場合 Flags 属性を enum に指定します。
Flags 属性を指定したからと言って、自動的に値が 0, 1, 2, 4, 8 のように設定されるわけではありません。
例えば、 「北西」を表すように Direction.North かつ Direction.West を意味するように、 論理和の演算 | を用いて次の 1 行目のように書けます。
var nw = Direction.North | Direction.West;
Console.WriteLine($"{nw:G} ({nw:d})");
// North, West (9)
この例でフラグの文字列として North, West が出力されていますが、これは Flags 属性を指定してあるためです。
Enum の HasFlag() メソッドを使うことで、特定のフラグが ON か OFF かチェックすることができます。
if (nw.HasFlag(Direction.North))
{
// ...
}
この条件式は次の従来の条件式と同じ意味になります。
if ((nw & Direction.North) == Direction.North)
{
// ...
}