C#のenumにフィールド・メソッドを定義したいとき【JavaからC#へ】


#コード抜粋

```c#:自分でEnum定義する方法.cs
public class AppState
{
    //フィールド一覧
    public readonly string viewStr;
    public readonly int waitTime;
    //コンストラクタ
    private AppState(string viewStr, int waitTime)
    {
        this.viewStr = viewStr;
        this.waitTime = waitTime;
    }
    //メソッド
    public string getViewStr()
    {
        return this.viewStr;
    }

    // 参照用インスタンス
    public static readonly AppState Active = new AppState("アクティブ", 10);
    public static readonly AppState Paused = new AppState("ポーズ", 20);
    public static readonly AppState Exit = new AppState("イグジット", 30);
}
```

#はじめに

JavaのEnumでは各列挙子にフィールド・メソッドを定義できますが、C#ではできません。代わりに使える方法を探しました。
↓　Javaならこのように書きたいとき。。。

```java:appState.java
enum AppState
{
    Active("アクティブ"), Paused("ポーズ"), Exit("イグジット");

    public final String viewStr;
    AppState(String viewStr){
        this.viewStr = viewStr;
    }
}
class Main
{
	public static void main (String[] args) throws java.lang.Exception
	{
	    System.out.println(AppState.Active.viewStr);    // <- enumのフィールド呼び出し
	}
}
```

#簡易な方法：拡張メソッドを使う
C#の構文の拡張メソッドを使用すると便利です。拡張メソッドは静的メソッドをインスタンスメソッドのように呼び出せる機能です。引数のないメソッドを定義することで、実質的にフィールドを定義したように扱うこともできます。

```c#:appState.cs
public enum AppState
{
    Active, Paused, Exit
}
public static class AppStateExt
{
    private static Dictionary<AppState, string> viewStrDictionary = new Dictionary<AppState, string>()
    {
        {AppState.Active,"アクティブ" },
        {AppState.Paused,"ポーズ" },
        {AppState.Exit,"イグジット" }
    };
    public static string viewStr(this AppState state)       //<-　拡張メソッド
    {
        return viewStrDictionary[state];
    }

}
class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine(AppState.Active.viewStr());       // <- インスタンスメソッドのように呼び出せる
    }
}
```

この方法には弱点があります。定義したいフィールドが多いとき、フィールドの数だけDictionaryを定義するため行数が多くなりがちです。

```c#:フィールド増やした場合.cs
    private static Dictionary<AppState, string> viewStrDictionary = new Dictionary<AppState, string>()
    {
        {AppState.Active,"アクティブ" },
        {AppState.Paused,"ポーズ" },
        {AppState.Exit,"イグジット" }
    };
    private static Dictionary<AppState, int> waitTimeDictionary = new Dictionary<AppState, int>()    //<-　追加したフィールド
    {
        {AppState.Active,10 },
        {AppState.Paused,20 },
        {AppState.Exit,30 }
    };
    //（以下、フィールドの数だけ続く。。。）

```

多くのフィールドを扱いたいときは↓の方法をオススメします。

#本格的な方法：自分でEnumを定義する
↓を参考にしたものです。
> C#でタイプセーフEnumパターン
> http://bleis-tift.hatenablog.com/entry/20080808/1218133517

参照用インスタンスを定義する箇所に、各インスタンスのフィールド値をまとめて記述できるので読みやすくなります。
フィールド・メソッド呼び出しもかなりJavaっぽいです。

```c#:自分でEnum定義.cs
public class AppState
{
    //フィールド一覧
    public readonly string viewStr;
    public readonly int waitTime;
    //コンストラクタ
    private AppState(string viewStr, int waitTime)
    {
        this.viewStr = viewStr;
        this.waitTime = waitTime;
    }
    //メソッド
    public string getViewStr()
    {
        return this.viewStr;
    }

    // 参照用インスタンス
    public static readonly AppState Active = new AppState("アクティブ", 10);
    public static readonly AppState Paused = new AppState("ポーズ", 20);
    public static readonly AppState Exit = new AppState("イグジット", 30);
}

class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine(AppState.Active.viewStr);         //<- フィールド呼び出し
        Console.WriteLine(AppState.Active.getViewStr());    //<- メソッド呼び出し
    }
}
```



#参考

C# の enum に関連する小技。
https://qiita.com/tricogimmick/items/38fe86a09e8e0865d471





<!--
？？　ステートマシンってENUM代わりになる？

? 応用：ステートマシン
ステートマシンには遷移の扱いで2種類あるっぽいです。

- 遷移は定義せずに、任意の状態間での遷移を許容するやり方
- 状態と遷移を定義して、特定の状態間での遷移のみ許容するやり方

?? 遷移は定義せずに、任意の状態間での遷移を許容するやり方

Unity向け　オレオレステートマシン
http://yamayatakeshi.jp/%E4%BF%BA%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E5%A4%A7%E9%83%A8%E5%88%86%E3%81%AF%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88%E3%83%9E%E3%82%B7%E3%83%B3%E3%81%A7%E8%A1%A8%E7%8F%BE/

?? 状態と遷移を定義して、特定の状態間での遷移のみ許容するやり方

↓　では、Enumで状態・遷移にタグ付けしてステートマシンを表現するサンプルがあります。
https://stackoverflow.com/questions/5923767/simple-state-machine-example-in-c

拡張メソッドを利用することで、状態・遷移を表現するEnumにフィールドを付与できます。

```c#:stateMachine.cs


```

Simple state machine example in C#?
https://stackoverflow.com/questions/5923767/simple-state-machine-example-in-c

-->