潜伏バグからのロングフリーズ

Javaっぽいエンジニアの徒然草

C#の列挙型(enum)でstring型を扱いたい場合は拡張メソッドを利用しよう

ほぼ半年振りとなりました。

ここだけの話もう2015年になっているらしいので更新してみます。

JavaっぽいエンジニアがC#を扱ったが為にアレコレ苦労しているというお話です。

 

C#の列挙型(enum)では、許容される型が以下に制限されています。
 ・byte
 ・sbyte
 ・short
 ・ushort
 ・int
 ・uint
 ・long
 ・ulong

数値型ばっかりです('A`)

そのため、Javaenumを扱うようにstringなどを使用することができません。

C#enumでstringなどの許容されていない型を使用する方法を調べたところ、

拡張メソッドを利用すると良さそうだったのでメモします。

 

例として、進捗を表すステータス「未着手」「作業中」「承認待ち」「承認済み」を

enum定義してstring型でステータス文字列が欲しい場面を考えます。

 

サンプルコード

1. namespace Xxx.Yyy.Zzz
2. {
3.     public enum XxxStatus
4.     {
5.         NotYetStarted, // 未着手
6.         Working, // 作業中
7.         ApprovalPending, // 承認待ち
8.         Approved // 承認済み
9.     }
10.
11.     // 拡張クラス
12.     public static class XxxStatusExt
13.     {
14.         // 拡張メソッド
15.         public static string ObtainStatus(this XxxStatus value)
16.         {
17.             string[] values = {"未着手", "作業中", "承認待ち", "承認済み"};
18.             return values[(int)value];
19.         }
20.     }
21. }

 

3〜9行目でenumを定義しています。

12〜20行目でenumの拡張クラスを定義しています。

拡張クラスは静的クラス(static)として定義する必要があります。

15〜19行目でXxxStatusクラス(今回はenum)の拡張メソッドを定義しています。

拡張メソッドは静的メソッド(static)として定義する必要があります。

15行目で一見すると拡張メソッドの引数を定義している箇所がありますが、これは引数ではありません。

最初のパラメータは、メソッドが操作する型をあらわします。

ここには、型の前にthis修飾子を付加する必要があります。

メソッドの引数は、最初のパラメータ以降に記載します。

つまり上記例では、

public static string ObtainStatus(this XxxStatus value)

となっていることから、

 ・XxxStatusの拡張メソッドである

 ・メソッドの引数は無し

という意味になります。

public static string ObtainStatus(this XxxStatus value, int num)

とすると、

 ・XxxStatusの拡張メソッドである

 ・メソッドの引数はint型のnum

という意味になります。

※引数にはthis修飾子はつけません。

 

拡張メソッドの話は一旦置いておいて、次にenumのお話です。

C#enumでは明示的にキャストすることで、何番目に定義されたかをint型で取得することが可能です。

上記例ではenum定義が

 ・NotYetStarted

 ・Working

 ・ApprovalPending

 ・Approved

の4つなので、int型にキャストすると考えると

 [0] NotYetStarted

 [1] Working

 [2] ApprovalPending

 [3] Approved

となります。この辺の考え方は配列と同様になります。

 

以上のことからサンプルソースの動作は、以下のようになります。

XxxStatus.NotYetStarted.ObtainStatus();
-> "未着手"

XxxStatus.Working.ObtainStatus();
-> "作業中"

XxxStatus.ApprovalPending.ObtainStatus();
-> "承認待ち"

XxxStatus.Approved.ObtainStatus();
-> "承認済み"

 

無事enumでstring型を扱う事が出来ました。

 

既存クラスに変更を加えずに機能拡張が可能という「拡張メソッド」は便利です。

知らない人から見ると理解できないコードになるのが難点ですが、

少し調べれば納得出来ると思うので、使える場面では使って行こうと思います。