すごい広島 172のメモ
以下のJSONをUnityで読み込みたい。
{
"type": "Point",
"value": {
"x": 1,
"y": 2,
"z": 3,
}
}
{
"type": "Press",
"value": {
"code": "a",
}
}
typeによってvalueの中身が違うようなJSONです。
JsonUtilityではDictionary型への変換はできなくて、変換する先の型を用意する必要がある。
こういったタイプの読み込み型の方針については公式にもちゃんとかいてある。
型が未知の場合の FromJson() の使用
JSON を「共通」のフィールドを持つクラスか構造体にデシリアライズします。それから、そのフィールドの値を利用して、2 度目のデシリアライズで実際に求める型にします。
http://docs.unity3d.com/jp/current/Manual/JSONSerialization.html
ということで以下のような4つのクラスを用意する。
// typeを読むためのクラス
[Serializable]
class SeekJSONType {
public string type;
}
// typeがわかった後に使うルート要素のクラス
[Serializable]
class Envelope<Value> {
public string type;
public Value value;
}
[Serializable]
class PointMessage {
public float x;
public float y;
public float z;
}
[Serializable]
class PressMessage {
public string code;
}
以下のように使う
var seekType = JsonUtility.FromJson<SeekJSONType>(str);
switch (seekType.type) {
case "Point":
var point = JsonUtility.FromJson<Envelope<PointMessage>>(str);
// pointを使った処理
break;
case "Press": {
var press = JsonUtility.FromJson<Envelope<PressMessage>>(str);
// pressを使った処理
break;
}
}
実行例
コード。
using UnityEngine;
using System.Collections;
using System;
// typeを読むためのクラス
[Serializable]
class SeekJSONType {
public string type;
}
// typeがわかった用のルート要素のクラス
[Serializable]
class Envelope<Value> {
public string type;
public Value value;
}
[Serializable]
class PointMessage {
public double x;
public double y;
public double z;
}
[Serializable]
class PressMessage {
public string code;
}
public class JsonFromSample : MonoBehaviour {
// Use this for initialization
void Start () {
read ("{\"type\":\"Point\",\"value\":{\"x\":1,\"y\": 2,\"z\":3}}");
read ("{\"type\":\"Press\",\"value\":{\"code\":\"a\"}}");
}
void read (string jsonString) {
var seekType = JsonUtility.FromJson<SeekJSONType>(jsonString);
switch (seekType.type) {
case "Point":
var point = JsonUtility.FromJson<Envelope<PointMessage>> (jsonString).value;
Debug.Log (String.Format("Point<{0},{1},{2}>", point.x, point.y, point.z));
break;
case "Press":
var press = JsonUtility.FromJson<Envelope<PressMessage>>(jsonString).value;
Debug.Log (String.Format("Press<{0}>", press.code));
break;
}
}
// Update is called once per frame
void Update () {
}
}
実行結果。
感想
ジェネリクスが使えてちょっと楽ができた。
switchが文字列でも使えてちょっと楽ができた。
C#細かいところわからないので、Scalaでかけたらいいなって個人的には思った。