ここでは列挙体の基本とその操作について、また列挙体の暗黙の基底クラスであるEnumクラスについて見ていきます。
列挙体を用いると関連のある一連の数値定数をひとまとめに扱うことができます。 .NET Frameworkにおいては、列挙体は個々の言語に特有な機能としてではなく、フレームワークでその基本的な機能が提供されています。 なお、列挙型という用語が用いられる場合がありますが、ここでは.NET Frameworkのドキュメントに合わせて列挙体に統一します。
列挙体の基本
列挙体の様々な機能を説明するのに先立って、もっとも基本的な列挙体の使い方の例を挙げてみます。
実行結果については省略しますが「d は北向きです」と表示されるはずです。 この例のように、東西南北という一連の方角を表す定数は、それぞれバラバラに存在するよりも一つのグループとして存在しているべきです。
もちろん、何らかの理由で単なる定数としてあつかった方がよい場合もありますが、一方で、列挙体の場合は値としても名前(つまり値の意味)としても表記でき、それらを結びつけておくことが出来ます。 定数では、定数として与えられているその値しか表記できません。
このように、列挙体の値の名前を文字列として表記することも可能ですし、値が内部的に保持している数値として表記することも可能です。 このように、列挙体の値が数値を持つだけでなく、意味も同時に持つことができる点で単なる定数より優れているといえます。
列挙体の値と型
列挙体定数の値
列挙体の定数一つ一つを宣言する際に、値を指定することができます。 なにも指定しない場合は、上から順に0, 1, 2...となっていきます。 その定数に特別な数値を与える場合、数値が意味を持つ場合には数値を指定することができます。
この例では上下方向を表す列挙体UpAndDownを宣言し、その各定数に値を与えています。 そして、upDownが上下(または方向なし)のうちどこを向いているかによってY座標の位置をずらしています。 このように、列挙体定数の値を直接利用することができます。
値を与える場合、複数の列挙体定数に同じ値を設定することができますが、その場合は次の例で示すような現象が発生します。
この例ではSameValueEnumのValueCにValueAと同じ値を指定しています。 実行結果を見てわかるとおり、一度目の表示では正しく ValueBが表示されていますが、二度目の表示ではeにValueCを割り当てたはずなのにValueAと出力されてしまっています。 これは列挙体の定数は内部では結局数値として扱われてしまうのでこのようになるのです。 ValueAとValueCに相当する定数が互いに別名であるような場合には問題ありませんが、この例のようにValueCと出力されることを期待する場合には注意が必要です。
列挙体定数の型
先の例のように列挙体定数の値を直接利用するようになると、列挙体定数の値の型が気になってきます。 そのような場合、列挙体の値の型を明示的に指定することができます。 指定できる型は、列挙体の性質からchar型以外の整数型に限られます。 また、なにも指定しなかった場合は既定でint(Integer)になります。 次の例は列挙体定数の型をshortにした例です。
列挙体に対する操作
列挙体は単純な定数に比べ様々な機能を持っています。 また、列挙体に対する操作もいろいろあります。 列挙体の暗黙の基底クラスであるEnum型には様々な静的メソッドが存在します。
値の名前の取得 (GetName)
GetNameメソッドを使用すると、指定された値から該当する数値をもつ列挙体の定数の名前を取得することが出来ます。
このように、指定された数値に対応する定数の名前を取得することができます。 また、対応する定数がない場合はnullが返されます。
すべての名前・値の取得 (GetNames, GetValues)
単一の値から名前を取得するのではなく、列挙体に含まれるすべての定数の名前を取得するにはGetNamesメソッドメソッドを、すべての定数の値を取得するには GetValuesメソッドを使用します。 この例を次に示します。
Enum.GetValues()メソッドが実際に返す配列の型は、列挙体の値の型と同じものになります。 int(Integer)型の列挙体の場合は、int(Integer)型の配列が返されます。
値が定数として宣言されているか (IsDefined)
任意の値が列挙体定数として宣言されているか否かを知るには、IsDefinedメソッドを使用します。
文字列からの変換 (Parse)
文字列(もしくは文字列化された数値)から列挙体の値を取得するには、Parseメソッドを使用します。 このメソッドでは、大文字・小文字の違いを無視するかどうかを指定することも出来ます。
文字列への変換 (ToString)
列挙体の値を文字列化するには、、ToStringメソッドを使用します。 引数で文字列化する際の書式を指定することも出来ます。
列挙体に対して指定できる書式文字列については書式指定子 §.列挙型の書式指定子で詳しく解説しています。
値が特定のフラグを持つか (HasFlags)
.NET Framework 4より、FlagsAttributeの付いた列挙体の値が特定のフラグを持つかどうか調べるためのメソッドHasFlagが追加されています。 FlagsAttributeについては、列挙体とフラグで詳しく解説します。
HasFlagメソッドの説明によると、このメソッドは次のビット演算と同じ結果を返すとされています。
The HasFlag method returns the result of the following Boolean expression.
thisInstance And flag = flag
Enum.HasFlag Method (Enum)
HasFlagsメソッドとビット演算を使った場合の記述を比較すると次のようになります。 上記のとおり、以下のどちらも同等の処理となります。
HasFlagメソッドを使うとコードは見やすくなる一方で、ビット演算を使った場合と比べてパフォーマンスは劣化します。 そのため、速度が優先される場合や繰り返しフラグの比較を行う状況ではあまり使いやすいものではありません。 参考までに、HasFlagsメソッドとビット演算での速度を比較した結果を示します。