Unity 5.3で実装されたJsonUtilityの注意点まとめ【改訂版】

この記事は2015年に執筆されたブロマガを改訂したものです。

Unity5.3のJsonUtilityを使ってみた感想と注意点です。

インスタンスJSONに、JSONインスタンスに変換するものである

変換する以外のことはできない
例えば、JSONライブラリと聞いて思い浮かべる、「変数名や構文の文字列をキーとして値を取り出す」ような機能はない。
データ形式を必ずC#のクラスとして記述しておく必要があるので、どんな名前の変数があるのか開発段階で未知である箇所には手が出せない。

クラスや構造体には[Serializable]属性、フィールドはpublicまたは[SerializeField]属性がついている必要がある

JsonUtilityは、Unityの根本的なアセットシリアライザと同じ原理で動いている。
そのため、シリアライズされるか否かの条件は、MonoBehaviourのフィールドになるか否かだと考えておくと外れがない。

DictionaryやHashtableはシリアライズできない

公式にも呼びかけられている大事なポイント。
シリアライズ前に、KeysとValuesを変換して保持しておく用のListや配列が必要になるかもしれない。

配列のネストは1つまで

多次元配列、配列内配列(ジャグ配列)、配列のコレクションなどは、JSONシリアライズしてくれない。
int[,] 、 int[][] 、 List<int[]> 、 List<List<int>> といった型は、JsonUtilityにスルーされてしまう。
公式によれば、他のシリアライザの5倍以上の速度があるそうなので、Array.ConvertAll とか String.Join とかを使って、配列を自力で文字列に変換する余裕はあるかも?

また、もっと楽な解決方法としては、配列の中のクラスの中の配列はOK
例えば、int のフィールドが1つあるだけのクラス AnotherClass を用意して、元のクラスには AnotherClass のフィールドを用意する。すると普通にシリアライズしてくれる。
自力変換に比べて楽だけど、大量のデータを扱う場合容量が嵩むので注意。
もちろんListでもいいし、クラスではなく構造体でも大丈夫。

OnBeforeSerialize と OnAfterDeserialize は呼ばれない

なぜならこれらはUnityメッセージ(OnEnable とか OnApplicationPause とかの類)であって、MonoBehaviourがアセットとしてシリアライズされる時にしか呼ばれない。
たとえScriptableObjectをJSON化する際であっても、JsonUtilityによって呼ばれることはない。

この2つを使わず、ISerializationCallbackReceiver を使うか、クラスにSerialize/Deserializeメソッドを記述するのがいいと思う。

非同期で実行できる

UnityEngine名前空間の機能の多くは普通別スレッドで動かせないけど、これに関しては全然OK。