SwitchEnum() というメソッドで,列挙型の値を交互に切り替える方法を御紹介いたします。
(Unity 2019.4.17f1)
始めに
本稿は,以下の記事の続編です。
「絶対値を同じくする正負の数を定数とした列挙子のペアを作り,定数 -1 を乗算する事で交互に切り替える」という方法を解説しました。
前回のコード(簡略版)
NewBehaviourScript.cs
using UnityEngine; public class NewBehaviourScript : MonoBehaviour { // 状態 enum State { A = -1, B = 1 C = -2, D = 2 }; // 状態切り替え定数 const int Switch = -1; void Update() { // クリック(タップ)開始 if (Input.GetMouseButtonDown(0)) { // state 切り替え state = (State)((int)state * Switch); } } }
中身が-1
である定数Switch
を掛ける事で,列挙型state
を交互に切り替えられます。
この方法には,以下のような問題点がありました。
「* Switch」という記法の可読性
型のキャストを記述する手間
今回はこれらの問題を,処理のメソッド化によって解決したいと思います。
新しいコード
まずは,メソッド側のスクリプトを準備します。
余計に複雑になっているように見えますが,呼び出し時の使い勝手を重視したためです。
細かい解説の前に,呼び出し元のスクリプトも見てみましょう。
NewBehaviourScript.cs
using UnityEngine; // SwitchEnum() のため using TsuGames; public class NewBehaviourScript : MonoBehaviour { /// <summary> /// 状態 /// </summary> enum State { A = -1, B = 1, C = -2, D = 2 }; [SerializeField, Tooltip("状態")] State state = State.A; void Update() { // クリック(タップ)開始 if (Input.GetMouseButtonDown(0)) { // state 切り替え state.SwitchEnum(); /* ↓本来このようにも書ける↓ */ //EnumExtentions.SwitchEnum(ref state); } } }
呼び出し時の記述はstate.SwitchEnum()
です,簡単でしょう?
EnumExtentions.SwitchEnum(ref state)
と書いても処理は同じなのですが,短く書けるようにメソッド側のスクリプトで工夫したというわけです。
それでは,その工夫について解説いたします。
解説
列挙型を扱うメソッドは,通常のクラスや構造体を扱うメソッドよりも複雑です。
なぜなら特定の列挙型をメソッド側で指定することは無意味であり,呼び出し側で用意されたあらゆる列挙型に対応せねばならないからです。
今回の例では呼び出し側のスクリプトでState
という列挙型を用意していますが,このState
という列挙型しか扱えないメソッドを作っても仕方ないですよね。
そこで,ジェネリックメソッドを利用します。
メソッド名に<T>
が付いている物が,ジェネリックメソッドです。
この宣言によってSwitchEnum()
は,あらゆる型を操作できるようになりました!
……いや,それは困りますよね。
int
やVector3
では使えないようにしながら,列挙型にだけ対応させたいわけです。
そこで必要になるのが,where
句による型制約です。
パラメータの後ろに付いているwhere T : struct, Enum
の部分ですね。
ここでEnum
に制約しているため,列挙型のみを扱えるメソッドに設定できました(struct
制約については後ほど)。
ここまで解説した部分で実現できるのは,EnumExtentions.SwitchEnum(ref state)
という呼び出しかたです。
これをstate.SwitchEnum()
という記述でも呼び出せるようにするため,拡張メソッド化します。
引数に取る列挙型を書き換える必要があるため,拡張メソッドの第1引数にはref
キーワードを用います(C# 7.2 以降の機能)。
この機能は構造体struct
にのみ適用されるため,struct
型制約も必要となるわけです。
拡張メソッドの呼び出し時にはref
キーワードを省略できるので,簡潔な記述が出来るようになりました。
終わりに
前回の案で挙がった問題点は,解消されていると思います。
C# のバージョンアップによって,列挙型のメソッドも以前より作りやすくなりましたね。
またなにか,面白い提案が出来ればと思います。
以上,2つの状態を同じ命令で切り替える方法の改良案でした。