(Unity) Dictionary를 Json 데이터로 파싱하기!

고현서·2022년 12월 7일
2

Json

목록 보기
4/4

Dictionary를 Json 데이터로 파싱하기

놀랍게도 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 파일로 저장하는 코드이다.

1. 먼저 Dictionary를 클래스 형식으로 key, value를 만들어 구성해줬다.

[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도 고려하여 제네릭 타입으로 만들어주었다.

2. ToJson, FromJson을 따로 만들어주기

/// <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.cs)

아래는 최종적으로 내가 만든 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;

    }
}

사용부분(MonsterJson.cs)

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);
    }

}

이로 인해 개발자들이 개발하기 편해졌으면 좋겠다.

profile
New 현또의 코딩세상 / Unity 개발자

1개의 댓글

comment-user-thumbnail
2023년 7월 20일

프로젝트 진행 도중 Dictionary 를 Json으로 변동하는데 도움 많이 되었습니다.
근데 작성하신 코드를 이용해도 바로 Json으로 적용되진 않더군요
DictionaryJsonUtility.ToJson은 너무 잘 적용되는데
DictionaryJsonUtility.FromJson이 잘 되지 않던 문제였습니다.

public static Dictionary<TKey, TValue> FromJson<TKey, TValue>(string jsonData)
    {
        JsonDataArray<TKey, TValue> dataList = JsonUtility.FromJson<JsonDataArray<TKey, TValue>>(jsonData);
        Dictionary<TKey, TValue> returnDictionary = new Dictionary<TKey, TValue>();
        for (int i = 0; i < dataList.data.Count; i++)
        {
            DataDictionary<TKey, TValue> dictionaryData = dataList.data[i];
            returnDictionary[dictionaryData.Key] = dictionaryData.Value;
        }
        return returnDictionary;
    }

로 수정하고 나니 동작이 잘 적용되었습니다.
dataList의 구조만 수정하였습니다.

답글 달기