놀랍게도 Dictionary형식은 Json 데이터로 파싱이 안된다!!
그렇기에 한번 데이터를 후처리 후 파싱을 시켜야한다.
[Serializable]
public class Monster
{
public string AttackType;
public float Power;
public int Age;
}
[Serializable]
public class MonsterList
{
public Dictionary<string, Monster> monsters;
}
public class MonsterJson : MonoBehaviour
{
private void Start()
{
Dictionary<string, Monster> monsterDic = new Dictionary<string, Monster>();
Monster zombie = new Monster();
zombie.AttackType = "Bite";
zombie.Power = 10;
zombie.Age = 100;
Monster wizard = new Monster();
wizard.AttackType = "Magic";
wizard.Power = 30;
wizard.Age = 30;
Monster dracula = new Monster();
dracula.AttackType = "Bite";
dracula.Power = 20.5f;
dracula.Age = 10000;
monsterDic["Wizard"] = wizard;
monsterDic["Dracula"] = dracula;
monsterDic["Zombie"] = zombie;
MonsterList Monster = new MonsterList();
Monster.monsters = monsterDic;
}
}
데이터를 Dictionary로 저장 후 JsonUtility로 ToJson하여 파일로 저장해보면, 아무것도 저장되지 않는 것을 볼 수 있다.
이는 JsonUtility가 Dictionary를 직렬화하지 못해서 발생한 일이다.
아래의 코드는 내가 작성한 Dictionary를 후처리 후 파싱하여 txt 파일로 저장하는 코드이다.
[Serializable]
public class DataDictionary<TKey,TValue>
{
public TKey Key;
public TValue Value;
}
[Serializable]
public class JsonDataArray<TKey, TValue>
{
public List<DataDictionary<TKey, TValue>> data;
}
여기서 다른 Dictionary도 고려하여 제네릭 타입으로 만들어주었다.
/// <summary>
/// Dictionary를 Json으로 파싱하기
/// </summary>
/// <typeparam name="TKey">Dictionary Key값 형식</typeparam>
/// <typeparam name="TValue">Dictionary Value값 형식</typeparam>
/// <param name="jsonDicData"></param>
/// <returns></returns>
public static string ToJson<TKey, TValue>(Dictionary<TKey, TValue> jsonDicData, bool pretty = false)
{
List<DataDictionary<TKey, TValue>> dataList = new List<DataDictionary<TKey, TValue>>();
DataDictionary<TKey, TValue> dictionaryData;
foreach (TKey key in jsonDicData.Keys)
{
dictionaryData = new DataDictionary<TKey, TValue>();
dictionaryData.Key = key;
dictionaryData.Value = jsonDicData[key];
dataList.Add(dictionaryData);
}
JsonDataArray<TKey, TValue> arrayJson = new JsonDataArray<TKey, TValue>();
arrayJson.data = dataList;
return JsonUtility.ToJson(arrayJson, pretty);
}
/// <summary>
/// Json Data를 다시 Dictionary로 파싱하기
/// </summary>
/// <typeparam name="TKey">Dictionary Key값 형식</typeparam>
/// <typeparam name="TValue">Dictionary Value값 형식</typeparam>
/// <param name="jsonData">파싱되었던 데이터</param>
/// <returns></returns>
public static Dictionary<TKey, TValue> FromJson<TKey, TValue>(string jsonData)
{
List<DataDictionary<TKey, TValue>> dataList = JsonUtility.FromJson<List<DataDictionary<TKey, TValue>>>(jsonData);
Dictionary<TKey, TValue> returnDictionary = new Dictionary<TKey, TValue>();
for(int i = 0; i < dataList.Count; i++)
{
DataDictionary<TKey, TValue> dictionaryData = dataList[i];
returnDictionary[dictionaryData.Key] = dictionaryData.Value;
}
return returnDictionary;
}
Dictionary형식을 직렬화하지 못하는 JsonUtility의 ToJson과 FromJson을 개발자가 Dictionary형식 또한 직렬화하여 저장할 수 있도록 했다.
또한 이 코드는 static 클래스로 풀어서 어디서든 이 Utility를 사용할 수 있도록 만들어줬다.
아래는 최종적으로 내가 만든 DictionaryJsonUtility 코드이다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class DataDictionary<TKey, TValue>
{
public TKey Key;
public TValue Value;
}
[Serializable]
public class JsonDataArray<TKey, TValue>
{
public List<DataDictionary<TKey, TValue>> data;
}
public static class DictionaryJsonUtility
{
/// <summary>
/// Dictionary를 Json으로 파싱하기
/// </summary>
/// <typeparam name="TKey">Dictionary Key값 형식</typeparam>
/// <typeparam name="TValue">Dictionary Value값 형식</typeparam>
/// <param name="jsonDicData"></param>
/// <returns></returns>
public static string ToJson<TKey, TValue>(Dictionary<TKey, TValue> jsonDicData, bool pretty = false)
{
List<DataDictionary<TKey, TValue>> dataList = new List<DataDictionary<TKey, TValue>>();
DataDictionary<TKey, TValue> dictionaryData;
foreach (TKey key in jsonDicData.Keys)
{
dictionaryData = new DataDictionary<TKey, TValue>();
dictionaryData.Key = key;
dictionaryData.Value = jsonDicData[key];
dataList.Add(dictionaryData);
}
JsonDataArray<TKey, TValue> arrayJson = new JsonDataArray<TKey, TValue>();
arrayJson.data = dataList;
return JsonUtility.ToJson(arrayJson, pretty);
}
/// <summary>
/// Json Data를 다시 Dictionary로 파싱하기
/// </summary>
/// <typeparam name="TKey">Dictionary Key값 형식</typeparam>
/// <typeparam name="TValue">Dictionary Value값 형식</typeparam>
/// <param name="jsonData">파싱되었던 데이터</param>
/// <returns></returns>
public static Dictionary<TKey, TValue> FromJson<TKey, TValue>(string jsonData)
{
List<DataDictionary<TKey, TValue>> dataList = JsonUtility.FromJson<List<DataDictionary<TKey, TValue>>>(jsonData);
Dictionary<TKey, TValue> returnDictionary = new Dictionary<TKey, TValue>();
for (int i = 0; i < dataList.Count; i++)
{
DataDictionary<TKey, TValue> dictionaryData = dataList[i];
returnDictionary[dictionaryData.Key] = dictionaryData.Value;
}
return returnDictionary;
}
}
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
[Serializable]
public class Monster
{
public string AttackType;
public float Power;
public int Age;
}
[Serializable]
public class MonsterList
{
public Dictionary<string, Monster> monsters;
}
public class MonsterJson : MonoBehaviour
{
private void Start()
{
Dictionary<string, Monster> monsterDic = new Dictionary<string, Monster>();
Monster zombie = new Monster();
zombie.AttackType = "Bite";
zombie.Power = 10;
zombie.Age = 100;
Monster wizard = new Monster();
wizard.AttackType = "Magic";
wizard.Power = 30;
wizard.Age = 30;
Monster dracula = new Monster();
dracula.AttackType = "Bite";
dracula.Power = 20.5f;
dracula.Age = 10000;
monsterDic["Wizard"] = wizard;
monsterDic["Dracula"] = dracula;
monsterDic["Zombie"] = zombie;
MonsterList Monster = new MonsterList();
Monster.monsters = monsterDic;
//ToJson 부분
string jsonData = DictionaryJsonUtility.ToJson(monsterDic, true);
string path = Application.dataPath + "/Data";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
File.WriteAllText(path + "/MonsterData.txt", jsonData);
//FromJson 부분
string fromJsonData = File.ReadAllText(path + "/MonsterData.txt");
MonsterList MonsterFromJson = new MonsterList();
MonsterFromJson.monsters = DictionaryJsonUtility.FromJson<string, Monster>(fromJsonData);
print(MonsterFromJson.monsters);
}
}
이로 인해 개발자들이 개발하기 편해졌으면 좋겠다.
프로젝트 진행 도중 Dictionary 를 Json으로 변동하는데 도움 많이 되었습니다.
근데 작성하신 코드를 이용해도 바로 Json으로 적용되진 않더군요
DictionaryJsonUtility.ToJson은 너무 잘 적용되는데
DictionaryJsonUtility.FromJson이 잘 되지 않던 문제였습니다.
로 수정하고 나니 동작이 잘 적용되었습니다.
dataList의 구조만 수정하였습니다.