先日、デジゲー博に行った際に購入した「Unityマニアックス」。
bootlegstore.stores.jp
これは、とても勉強になる。
なかでも特に気になったのが、この部分だ。
using UnityEngine; public class TestComponent : MonoBehaviour { private void Start() { PrintEnumList<EPet>(); PrintEnumList<ELanguage>(); } private void PrintEnumList<T>() where T : struct { System.Type type = typeof( T ); T[] values = (T[])System.Enum.GetValues( type ); Debug.LogFormat( "{0} enum list.", type.Name ); for( int i = 0; i < values.Length; ++i ) { Debug.Log( values[ i ] ); } } private enum EPet { Dog, Cat, Hamster, } private enum ELanguage { Japanese, English, } } // class TestComponent
そう、ジェネリックをenum
型として制約させたいときはstruct
を使えばいいということだ。
いろいろためになることが書いてある中、それを選ぶ?
と言われそうですが、この方法は探してたんですよ。
このジェネリック関数、またはクラスに指定したいのはenum
だ。
ただ、where
を使ってどう制約していいかがわからない。
enum
型を直接where
で指定することはできないし、かといって制約しなかったら何でもかんでも型を指定されてしまう……。
そんな中この本に書いてあった、struct
での制約方法だ。
そうか、enumが値型だ。
それならばstruct
で制約することが出来る。
この方法は思い浮かばなかった。
コードの戦略性がまた一つ広がった気がする。
……でも値型による制約ってことは、こんなこともできちゃうよね。
private void Start() { PrintEnumList<EPet>(); PrintEnumList<ELanguage>(); PrintEnumList<int>(); PrintEnumList<float>(); PrintEnumList<Sample>(); } private struct Sample { public int number; public float single; }
うん、ビルド通っちゃったよね。
int
とかfloat
とか、自分で作った構造体とかも指定できちゃうようね。
これ実行したらどうなるんだろう。
System.Enum.GetValues()
あたりでヤバイことになりそうだけど。
ArgumentException: enumType is not an Enum type.
トラップカードオープン、例外発動!
だよね、やっぱりそうなるよね。
うーん、struct
を使うことで制約性は跳ね上がったけど、完全ではないということか……。
どうしようかね。
解決案 その一
処理の中身を見れば、指定すべき型はenumでなければならないことは明白なはず。
にもかかわらず、enum以外の型を指定する糞プログラマーには鉄拳制裁を与える。
うん、それはちょっと横暴かな。
今回の例はわかりやすかったけど、ジェネリッククラスだったりしたら、問題となる処理がすぐそばにあるとは限らないからね。
解決案 その二
コメントで"enum型を指定してね♥"と記述しておく。
にもかかわらず、enum以外の型を指定する糞プログラマーには鉄拳制裁を与える。
うん、とりあえず暴力行為はやめようよ。
まあ、それでもいいような気がする。
でも折角なので、例外処理でも書いておこうよ。
private void PrintEnumList<T>() where T : struct { System.Type type = typeof( T ); T[] values = null; try { values = (T[])System.Enum.GetValues( type ); } catch( System.Exception i_exception ) { Debug.LogError( i_exception ); return; } Debug.LogFormat( "{0} enum list.", type.Name ); for( int i = 0; i < values.Length; ++i ) { Debug.Log( values[ i ] ); } }
えっ、例外処理とかダルイって。
うーん、それじゃあせめてアサーションだけでも。
確かSystem.Type
にはenum
かどうか判断するプロパティがあった気がするから。
private void PrintEnumList<T>() where T : struct { System.Type type = typeof( T ); Debug.AssertFormat( type.IsEnum, "is not an Enum type" ); T[] values = (T[])System.Enum.GetValues( type ); Debug.LogFormat( "{0} enum list.", type.Name ); for( int i = 0; i < values.Length; ++i ) { Debug.Log( values[ i ] ); } }
ふぅ、まあこんなところでしょうか。
それにしても、やっぱり技術書を読むのは勉強になります。
開発ばっかりもいいですが、たまには技術書もいろいろと読んでいかなくちゃいけませんよね。