【Unity】ISerializationCallbackReceiverを使いJsonUtilityでDictionaryを実現
Unity 2019.2.0f1 Personal(2019年8月)
UnityのJsonUtilityはほとんどの型をシリアル化できますが、
残念ながらDictionary型は対象外です。
が、ISerializationCallbackReceiverというインターフェイスを使うことで、
Dictionaryを実現することができます。
ISerializationCallbackReceiver
UnityEngine.ISerializationCallbackReceiver - Unity スクリプトリファレンス
ISerializationCallbackReceiverインターフェイスに備わっているメソッドは
OnBeforeSerializeとOnAfterDeserializeです。
OnBeforeSerializeはToJsonでクラスをJsonへシリアル化する前に、
OnAfterDeserializeはFromJsonでJsonをクラスへデシリアライズした後に呼ばれます。
この2つのメソッドを使い、Dictionaryを実現することができます。
今回はDictionaryのkeyにID(1,2,3)、valueにスキル名(fire,thunder,water)
を、Skillクラスで実現します。
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; [Serializable] public class Skill : ISerializationCallbackReceiver { public List<int> keys = new List<int> {1,2,3}; public List<string> values = new List<string> {"fire", "thunder", "water"}; public Dictionary<int, string> skillDictionary = new Dictionary<int, string>(); public Skill() { for (int i = 0; i != Math.Min(keys.Count, values.Count); i++) { skillDictionary.Add(keys[i], values[i]); } } // // ToJsonでクラスデータをJsonに変換する前 public void OnBeforeSerialize() { Debug.Log("OnBeforeSerialize"); keys.Clear(); values.Clear(); foreach (var s in skillDictionary) { keys.Add(s.Key); values.Add(s.Value); } } //// FromJsonでクラスデータを読み込んだ後 public void OnAfterDeserialize() { Debug.Log("OnAfterDeserialize"); skillDictionary = new Dictionary<int, string>(); // Math.Minで最小値を抽出 for (int i = 0; i != Math.Min(keys.Count, values.Count); i++) { skillDictionary.Add(keys[i], values[i]); } } }
Skill.cs
JsonUtilityの対象なのでクラスに[Serializable]の属性をつけます。
また先に説明したISerializationCallbackReceiverインターフェイスを実装します。
JsonUtilityはList型はシリアライズできるので、
keysとvaluesのList型変数を用意します。
更にskillDictionaryというDictionary型変数を用意します。
こちらはシリアライズ化できません。
OnBeforeSerializeメソッドはJsonUtility.ToJsonが実行される前に呼ばれます。
クラスデータがJsonに変換される前に、skillDictionaryのKeyとValueを
keys, valuesの各List型変数に移します。
これらはToJsonが実行された時にシリアライズされます。
OnAfterDeserializeメソッドはJsonUtility.FromJsonが実行された後に呼ばれます。
実行されるのはJsonデータがクラスデータに戻された後です。
skillDictionaryを初期化し、keys, valuesの各List型変数から値を抽出していきます。
これでデシリアライズ後にDictionary型変数を使用できるようになりました。
実行
それでは実際にDictionary型変数をシリアライズ/デシリアライズしてみます。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Manager : MonoBehaviour { void Start() { Skill profile = new Skill(); var json = JsonUtility.ToJson(profile); Debug.Log(json); var newProfile = JsonUtility.FromJson<Skill>(json); foreach (var p in newProfile.skillDictionary) { Debug.Log(p.Key +":"+p.Value); } } }
Manager.cs
ToJsonでシリアライズし、FromJsonでデシリアライズしているだけです。
ToJsonでシリアライズされたDictionaryデータは、
List型変数keys, valuesとして保存されています。
またFromJsonでデシリアライズされた後は
Dictionary型のskillDictionaryとして使用されています。
今回はここまでです、ありがとうございました〜