Version: 2020.3
脚本序列化错误
脚本编译

JSON 序列化

使用 JsonUtility 类可在 Unity 对象与 JSON 格式之间来回转换。例如,可以使用 JSON 序列化与 Web 服务进行交互,或者轻松地将数据压缩和解压缩为基于文本的格式。

JSON 序列化使用“结构化”JSON 的概念:创建一个类或结构来描述将在 JSON 数据中存储的变量。例如:

[Serializable]
public class MyClass
{
    public int level;
    public float timeElapsed;
    public string playerName;
}

此代码段定义了一个包含三个变量(__leveltimeElapsed__ 和 __playerName__)的普通 C# 类,并用 Serializable 属性标记该类,这样才能使用 JSON 序列化程序。要创建类的实例,可以使用如下所示的代码:

MyClass myObject = new MyClass();
myObject.level = 1;
myObject.timeElapsed = 47.5f;
myObject.playerName = "Dr Charles Francis";

然后使用 JsonUtility.ToJson 方法将其序列化(转换)为 JSON 格式:

string json = JsonUtility.ToJson(myObject);
// json 现在包含:'{"level":1,"timeElapsed":47.5,"playerName":"Dr Charles Francis"}'

要将 JSON 转换回对象,请使用 JsonUtility.FromJson

myObject = JsonUtility.FromJson<MyClass>(json);

此代码将创建一个新的 MyClass 实例,并使用 JSON 数据设置该实例的值。如果 JSON 数据包含的某些值未映射到 MyClass 中的字段,则序列化程序将忽略这些值。如果 JSON 数据缺少 MyClass 中某些字段的值,则序列化程序会在返回的对象中保留这些字段的构造值。

JSON 序列化程序当前不支持处理非结构化 JSON。也就是说,不能以任意键值对树的形式浏览和编辑 JSON。如果需要这样做,应采用功能更全面的 JSON 库。

用 JSON 覆盖对象

还可以在现有对象上反序列化 JSON 数据,从而覆盖所有现有数据:

JsonUtility.FromJsonOverwrite(json, myObject);

如果 JSON 数据不包含某个字段的值,则序列化程序不会更改该字段的值。此方法可重复使用先前创建的对象,从而可以将分配工作保持在最低限度。此方法还允许您故意用仅包含一小部分字段的 JSON 来覆盖对象以便“修补”对象。

警告:JSON 序列化程序 API 支持 MonoBehaviourScriptableObject 子类以及普通结构和类。但是,将 JSON 反序列化为 MonoBehaviourScriptableObject 子类时,必须使用 FromJsonOverwrite 方法。如果尝试使用 FromJson,则 Unity 会抛出异常,因为不支持此行为。

支持的类型

JSON 序列化程序 API 支持任何 MonoBehaviour 子类、ScriptableObject 子类或者带有 [Serializable] 属性的普通类或结构。将对象传入到标准 Unity 序列化程序进行处理时,需要遵循与在 Inspector 中相同的规则和限制:Unity 只序列化字段;不支持类似 Dictionary<> 的类型。

Unity 不支持将其他类型直接传递到 API,例如原始类型或数组。如果需要转换上述类型,则需要将它们包裹在某种 classstruct 中。

在 Editor 中且仅在 Editor 中有一个并行 API EditorJsonUtility,允许将 UnityEngine.Object 派生的任何对象与 JSON 进行互相序列化。这样生成的 JSON 将包含与对象的 YAML 表示相同的数据。

性能

基准测试表明,JsonUtility 比流行的 .NET JSON 解决方案要快得多,但此类在某些情况下提供的功能较少。

垃圾收集 (GC) 内存使用量为最低量:

  • ToJson 仅为返回的字符串分配 GC 内存。
  • FromJson 仅为返回的对象以及所需的所有子对象分配 GC 内存(例如,如果对包含数组的对象进行反序列化,则 Unity 将为该数组分配 GC 内存)。
  • FromJsonOverwrite 仅根据需要为写入的字段(例如字符串和数组)分配 GC 内存。这意味着,如果 JSON 覆盖的所有字段都是值类型,则 Unity 不会分配任何 GC 内存。

可以使用后台线程中的 JsonUtility API。但是,与任何多线程代码一样,在一个线程上序列化或反序列化对象时,请勿在另一个线程上访问或更改该对象。

控制 ToJson() 的输出

ToJson 方法支持完美打印 JSON 输出。此功能默认为关闭状态,但可通过传递 true 作为第二个参数来开启此功能。

可以使用 [NonSerialized] 属性在输出中省略字段。

使用包含未知类型的 FromJson()

如果事先不知道对象的类型,请将 JSON 反序列化为包含“公共”字段的类或结构,然后使用这些字段的值来计算出您想要的实际类型。然后第二次反序列化为该类型。

脚本序列化错误
脚本编译