unity json

Unity向けのJSON Parserを作成中

いつもJSONUtilやMiniJson+JsonNodeを使うのだけど数値周りのcastで苦しんだので自前でつくることにした。

UnityのJSON

UnityのJsonUtilityみたいなシリアライザ・デシリアライザと不可分のものは使いづらい。例えば、以下のようなjsonでpositionだけをデシリアライズしたい場合。

{
    "action": "hoge",
    "params": {
        "power": 9.8,
        "position": [0, 1, 2]
    }
}

なので、このあたりのスクリプトにいつも世話になっている。

ところが、MiniJsonが実装としてObjectの入れ物としてDictionary[string, object]、Arrayの入れ物としてList[object]を使っているのをキャストで取り出すときにUWPと.Net3.5の非互換性等ではまった。

int64 n=1234;
var no=(object)n;
var i=(int)no;

上記のような、ある数をobject型に代入してそれを違う型として取りだすようなときにExceptionが頻発するのに苦しんだのだ。

// これはちょっと・・・
var i=(int)(int64)no;
  • Objectから元に戻すときは同じ型でなければならない

とかルールがありそうな気がしたがちょっとその辺の言語仕様が見つからなかった。さらにMonoの.Net3.5とUWPの.Netで挙動が違うところもあるような気がした。そういう訳で、Objectに代入するのやめればいいじゃん、となった。

JsonSan

JSON, Util, Parse, Reader, Deserializer|Serializerあたりの組み合わせが使い尽くされていたのでリポジトリ名がすごい適当になった。JSONさん。

JSONの仕様を見ながらごりごりテストドリブンで実装したみた。

ObjectのキーがString限定なのに初めて気づいた。Stackoverflowで「JavascriptのObjectリテラルとJSONは違うのだよ」というのを見たが、まぁそうですね。コメントとかキーのクォート省略とか。

実装

JSON文字列をパーサーに入力したらパース済みのノードとして結果を得る。

var json="[ \"json\" ]";
var node=Node.Parse(json);

ノードはJSONの定義に沿った型をenumで知っていて、GetNumber(), GetString(), GetBoolean()等が実装してあるので適当に値を取り出せる。MiniJsonでのはまりを反省してNumber型はdouble決め打ちにした。

public enum ValueType
{
    Unknown,

    String,
    Number,
    Object,
    Array,
    Boolean,
}

Debug.Log(node.ValueType); // ValueType.String
node.GetString();

nodeがコレクション型の場合がミソでパースした時点では”{“または”[“までしか読まないことにした。子要素への要求が来た時点で中に読み進んでネストしたNodeを返せるようにした。

foreach(var child in node)
{
    Debug.Log(child.GetString());
}

わりといい感じにできたので引き続きシリアライザ・デシリアライザをこの上に構築して行く気になってきた。