【Unity】JsonUtility でObject を JSON 化できるパターンと出来ないパターン

DEVELOP

Object と JSON 文字列とを相互に変換してくれる Unity 公式の JsonUtility。速度も速く便利ですが、書き方を間違えるとJSON化されなかったりするので注意が必要です。

目次

JSON 化できる例

最もシンプルな構造

[System.Serializable]
public class Weapon
{
	// Id
	public int id;
	
	// 武器名
	public string name;
	
	// 攻撃力
	public int atk;
}
 
void Run()
{
	var weapon = new Weapon()
	{
		id = 1,
		name = "SWORD",
		atk = 5,
	};
 
	var json = JsonUtility.ToJson(weapon);
	Debug.Log(json);
}

class には System.Serializable 属性を付与します。

{
    "id": 1,
    "name": "SWORD",
    "atk": 5
}

JSON化出来ています。

入れ子にする

階層的な JSON ってよくありますよね。

[System.Serializable]
public class Status
{
	public int atk;
}
 
[System.Serializable]
public class Weapon
{
	public int id;
	public string name;
	public Status status;
}
 
void Run()
{
	var weapon = new Weapon()
	{
		id = 1,
		name = "SWORD",
		status = new Status()
		{
			atk = 5,
		},
	};
	var json = JsonUtility.ToJson(weapon);
	Debug.Log(json);
}

武器ステータスを class に分けて入れ子にしてみました。

{
    "id": 1,
    "name": "SWORD",
    "status": {
        "atk": 5
    }
}

階層でもJSON 出力されます。

配列やリスト

[System.Serializable]
public class Effect
{
	public int id;
}
 
[System.Serializable]
public class Status
{
	public int atk;
}
 
[System.Serializable]
public class Weapon
{
	public int id;
	public string name;
	public Status status;
	public Effect[] effect;
}
 
 
void Run()
{
	var weapon = new Weapon()
	{
		id = 1,
		name = "SWORD",
		status = new Status()
		{
			atk = 5,
		},
 
		effect = new Effect[]
		{
			new Effect()
			{
				id = 10,
			},
			new Effect()
			{
				id = 20,
			}
		},
	};
 
	var json = JsonUtility.ToJson(weapon);
	Debug.Log(json);
}
{
    "id": 1,
    "name": "SWORD",
    "status": {
        "atk": 5
    },
    "effect": [
        {
            "id": 10
        },
        {
            "id": 20
        }
    ]
}

サンプルは配列ですが List に変わっても結果は同じです。

JSON 化できない例

Dictionary

JsonUtility は Dictionary に対応していません。

[System.Serializable]
public class Effect
{
	public int value;
}
 
[System.Serializable]
public class Status
{
	public int atk;
}
 
[System.Serializable]
public class Weapon
{
	public int id;
	public string name;
	public Status status;
	public Dictionary<int, Effect> effect;
}
 
void Run()
{
	var weapon = new Weapon()
	{
		id = 1,
		name = "SWORD",
		status = new Status()
		{
			atk = 5,
		},
 
		effect = new Dictionary<int, Effect>()
		{
			{
				1,
				new Effect()
				{
					value = 10,
				}
			},
			{
				2,
				new Effect()
				{
					value = 20,
				}
			}
		}
	};
 
	var json = JsonUtility.ToJson(weapon);
	Debug.Log(json);
}
{
    "id": 1,
    "name": "SWORD",
    "status": {
        "atk": 5
    }
}

Dictionary にした Effect が無視されてしまいます。エラーログは出ません。

自動実装プロパティ

見落としがちですが get/set 書いちゃダメです。

[System.Serializable]
public class Weapon
{
	public int id		{ get; set; }
	public string name	{ get; set; }
}
 
void Run()
{
	var weapon = new Weapon()
	{
		id = 1,
		name = "SWORD",
	};
 
	var json = JsonUtility.ToJson(weapon);
	Debug.Log(json);
}

癖で書いてしまうことがあるかもしれません。

{}

何も出力されません。

手を加えるとJSON化できるもの

private な変数

private な変数はそのままでは JSON 化できません。

[System.Serializable]
public class Weapon
{
    private int id;
    private string name;
}

private な変数は SerializeField 属性を付与することで JSON 化できます。

[System.Serializable]
public class Weapon
{
	[SerializeField]
	private int id;
	[SerializeField]
	private string name;
}
 
void Run()
{
	var weapon = new Weapon(1, "SWORD"); 
	var json = JsonUtility.ToJson(weapon);
	Debug.Log(json);
}
{
    "id": 1,
    "name": "SWORD"
}

まとめ

これくらい網羅しておけば、迷うことも無いのではと思います。速度面でも結構早いのでうまく活用していきたいですね。

Posted by kazupon