数値指定時のトラブル例
以下は、数値指定時に起こるトラブルの一例である。内容としては、ただ単に列挙型の値をコンソールに出力しているだけで何も問題がないように見える。
1: using System;
2:
3: namespace ConsoleApplication9
4: {
5: enum Sample
6: {
7: A,
8: B,
9: C = 10,
10: D,
11: E = B
12: }
13: class Class1
14: {
15: static void Main(string[] args)
16: {
17: Console.WriteLine( Sample.A );
18: Console.WriteLine( Sample.B );
19: Console.WriteLine( Sample.C );
20: Console.WriteLine( Sample.D );
21: Console.WriteLine( Sample.E );
22: }
23: }
24: } |
|
数値指定時のトラブル例を示したサンプル・プログラム9 |
単に列挙型の値をコンソールに出力しているだけだが……。 |
これを実行すると以下のようになる。
|
サンプル・プログラム9の実行結果 |
“B”が出力されると予想される場所に“E”が表示されている。
|
見て分かるとおり、本来A〜Eが順に出力されるはずが、Bの表示がEに化けている。その原因は、11行目の“E = B”にある。列挙型が内部的に数値で処理されるため、同じ数値に割り当てられた名前は区別することができない。つまり、Sample.Bを使ったのか、Sample.Eを使ったのかは、列挙型の値からは区別できない。そこで、Sample.Bを指定しているのに、同じ値を持つEがコンソールに表示されてしまうという現象が起きるのである。これを回避するには、同じ値を別の名前に割り当てなければよい。数値を明示的に指定しなければ、自動的に同じ値の割り当ては回避されるので、初心者は数値指定を避けた方がトラブルに巻き込まれる危険が減る。
列挙型の数値計算
列挙型は数値ではないが、内部的に数値として処理される。そのため、すべてではないが、限定的な数値計算が実行できるようになっている。以下は列挙型を数値計算に用いたサンプル・ソースである。
1: using System;
2:
3: namespace ConsoleApplication10
4: {
5: enum Sample
6: {
7: A,
8: B,
9: C
10: }
11: class Class1
12: {
13: static void Main(string[] args)
14: {
15: Sample a = Sample.A;
16: Sample r = a + 1;
17: Sample b = Sample.B;
18: //Sample s = a + b; //演算子 '+' を 'ConsoleApplication10.Sample' と 'ConsoleApplication10.Sample' 型のオペランドに適用することはできません。
19: Console.WriteLine( r );
20: }
21: }
22: } |
|
列挙型を数値計算に用いたサンプル・プログラム10 |
列挙型の値同士の足し算はコンパイル・エラーとなる。 |
これを実行すると以下のようになる。
|
サンプル・プログラム10の実行結果 |
“A”に1を足したため、次の要素を示す“B”が表示されている。 |
16行目は、Aが代入されている変数aに1を足すコードが記述されている。このコードは正常に実行でき、結果はBとなる。これは、5〜10行目の列挙型の定義で、Aの次がBであることによる結果である。一方、18行目のように、列挙型の値と列挙型の値を足し算するような計算はエラー扱いとなり、コンパイルできない。Aに1を足すと次の要素を示す、という計算に意味はあっても、AとBを足す、という計算に意味はないからだ。
値の名前を得る
C#の列挙型は、すべてSystem.Enumクラスを継承したものとして自動的に定義される。そのため、System.Enumクラスを処理するためのさまざまなメソッドがすべて利用できる。例えば、列挙型のある値に対応する名前を得るには、以下のように記述することができる。
1: using System;
2:
3: namespace ConsoleApplication11
4: {
5: enum Era
6: {
7: Meiji,
8: Taisho,
9: Showa,
10: Heisei
11: }
12: class Class1
13: {
14: static void Main(string[] args)
15: {
16: Era t = Era.Taisho;
17: string name = Era.GetName( Type.GetType("ConsoleApplication11.Era"), t );
18: Console.WriteLine( name );
19: }
20: }
21: } |
|
列挙型の値に対応する名前を得るサンプル・プログラム11 |
System.EnumクラスにあるGetNameメソッドを使用している。 |
これを実行すると以下のようになる。
|
サンプル・プログラム11の実行結果 |
GetNameメソッドに列挙型の値を渡すと、それに対応している名前が文字列で返される。
|
ポイントは17行目である。GetNameメソッドは、System.Enumクラスのstaticなメソッドである。第1引数に列挙型の型を、第2引数に判定したい値を渡すと、列挙型の名前を返してくれる。つまり、Era.Taishoという値をGetNameメソッドの第2引数に渡すと、対応する文字列“Taisho”が返される。
列挙型のすべての名前を得る
System.Enumクラスには列挙型のすべての名前を得るメソッドもある。以下はそれを用いた例である。
1: using System;
2:
3: namespace ConsoleApplication12
4: {
5: enum Era
6: {
7: Meiji,
8: Taisho,
9: Showa,
10: Heisei
11: }
12: class Class1
13: {
14: static void Main(string[] args)
15: {
16: string [] names = Era.GetNames( Type.GetType("ConsoleApplication12.Era") );
17: foreach( string s in names )
18: {
19: Console.WriteLine( s );
20: }
21: }
22: }
23: } |
|
列挙型のすべての名前を得るサンプル・プログラム12 |
System.EnumクラスにあるGetNamesメソッドを使用している。 |
これを実行すると以下のようになる。
|
サンプル・プログラム12の実行結果 |
列挙型であるEra型に含まれるすべての要素の名前が列挙される。
|
16行目のGetNamesメソッドは、引数として与えられた列挙型に含まれるすべての名前を、文字列の配列として返す。これを調べれば、列挙型に含まれるすべての名前を容易にプログラム中で知ることができる。
Insider.NET 記事ランキング
本日
月間