Contents

03Json序列化

JSON序列化

JSON是一种通用的数据格式结构。Unity中有很多工具可以将Class转换成JSON结构并持久化。本文主要记录一些Unity中可以用到的JSON序列化库工具,并且做一些简单的对比。以方便将来JSON相关的时候进行处理。

目前看到主要有一些JSON序列化工具

  • JsonUtility
  • LitJson
  • Newtonsoft.Json

基础效率对比

工具名 序列化(ms) 反序列化 数据大小
次数 $10^6$ $10^5$
JsonUtility 4106 740 164
LitJson 20096 8553 175
Newtonsoft.Json 31540 4971 174

一个简单的序列化结果对比: 类型描述

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Serializable]
public class JsonTestTarget
{
    public string strValue;
    public int intValue;
    public float floatValue;
    public InnerJsonTestTarget innerTarget;
    public Dictionary<string, int> dictValue;
    public List<int> listValue;
}

[Serializable]
public class InnerJsonTestTarget
{
    public string strValue;
    public int intValue;
    public float floatValue;
}

序列化后的结果:

1
2
3
4
5
6
// JsonUtility 长度:164
{"strValue":"Test1","intValue":10,"floatValue":10.539999961853028,"innerTarget":{"strValue":"InnerTest1","intValue":1239,"floatValue":1940.0},"listValue":[2,3,5,7]}
// JsonLit 长度:175
{"strValue":"Test1","intValue":10,"floatValue":10.54,"innerTarget":{"strValue":"InnerTest1","intValue":1239,"floatValue":1940.0},"dictValue":{"key1":10},"listValue":[2,3,5,7]}
// Newtonsoft.Json 长度:174
{"strValue":"Test1","intValue":10,"floatValue":10.54,"innerTarget":{"strValue":"InnerTest1","intValue":1239,"floatValue":1940},"dictValue":{"key1":10},"listValue":[2,3,5,7]}

但每个工具都有细节,可以参看下面的说明:

JsonUtility

Unity自带的序列化工具,使用起来简单,速度是最快的。

官方文档说明,其序列化实例的类型必须是MonoBehaviour,ScriptableObject或者被Serializable attribute标注的普通Class/Struct。不支持的字段会被忽略,例如private field,static field以及那些被NonSerialized attribute标注的字段。

另一点是,尽量传递原始类型给该方法,因为有些情况下,其序列化结果不一定如预期一样。例如传递一个数组进入该方法,其不会产生一个包含每个元素的JSON数组,而是一个对象,包含了数组中对象的所有public field。

对于JsonUtility支持的序列化类型可参考Unity的Serialization Rule: https://docs.unity3d.com/Manual/script-Serialization.html

但是其实际支持的数据格式有限,支持以下类型:

  • 基础数据类型
    • 数字数据类型:int,float,double,decimal,long
    • 字符数据类型:char,string
    • Unity内置类型:Vector2,Vector3,Quarteration
  • 容器数据类型
    • 支持List,Array集合类型
    • 不支持Dictionary,Query,stack等集合类型,而且对应字段不会出现在json中。
  • 对于传入的类型,可以不用Serializable标注。但是如果其内部字段为某个类型,则对应类型需要用Serializable标注,才可以序列化。而且标注的类型被嵌套在List,Array中也可以被序列化。例如如下结构也可被序列化:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class JsonUtilityTarget
{
    public JsonInnerTarget innerValue;
    public List<JsonInnerTarget> innerList;
}

[Serializable]
public class JsonInnerTarget
{
    public int intValue;
}
  • 支持Enum枚举,但是值会转化成对应的数值值。

  • 对于浮点数序列化后的结果会带上浮点误差。例如10.54f=>10.539999961853028导致序列化后的结构会比较大

LitJson序列化

https://litjson.net/

LitJson是一个.Net库函数,用来处理往来Json格式的转换。 可以看到其速度对比JsonUtility要慢很多,。但是其支持对简单Dictionary的序列化操作。

  • JsonUtility不支持字段,LitJson支持(但是键只能是字符串)。
  • JsonUtility对自定义类型不要求有无参构造,LitJson则要求。
  • JsonUtility存储空对象时会存储默认值而不是null,LitJson会存null。

Newtonsoft序列化

https://www.newtonsoft.com/json

Newonsoft库是这三个里面序列化速度最慢的,但是其反序列化速度还可以。参考一些论坛讨论,其对于大数据的序列化反序列化都还是很客观的。另一方面是,他支持的数据类型是最广泛的。支持Dictionary的各种泛型嵌套。除这些之外,其库函数还有各种使用支持。

其他

主要是一些网络上对三者序列化的讨论,有助于对于Json序列化的思考。

提到与所有性能问题一样,对于Json序列化考虑效率之前。先完整思考一下从架构,工程角度是否有必要去使用Json序列化。而不是单单思考这些方式够不够快上面。 例如对于三种序列化,他们所支持的数据结构是不太一样的。而这部分则是要根据我们的使用场景来确定用那种方式合适。

这个2015年的文章里面,也做了相同的测试。同时的是也补充测试了更大更复杂的数据。可以看到此时NewtonsoftJson序列化则是最快的。