You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何JsonUtility.ToJson会将null类数组替换为默认实例化类数组?

问题原因

Unity内置的JsonUtility序列化系统存在设计限制:对于标记为[Serializable]的引用类型数组,当数组元素为null时,序列化过程会自动创建该类型的默认实例填充空位。这是因为JsonUtility基于Unity核心序列化框架构建,该框架为保证反序列化稳定性,默认不保留空引用,会自动用默认实例替代null元素。

解决方案

1. 用辅助标记字段记录空元素状态

在包含数组的类中添加布尔数组,专门记录对应位置元素是否为null,序列化前标记状态,反序列化后恢复null:

[Serializable]
public class PlayerStatHandler
{
    public Equipment[] m_equippedEquipment;
    public bool[] m_isElementNull; // 记录对应索引是否为null
}

序列化前处理:

// 初始化标记数组
m_playerStatHandler.m_isElementNull = new bool[m_playerStatHandler.m_equippedEquipment.Length];
for (int i = 0; i < m_playerStatHandler.m_equippedEquipment.Length; i++)
{
    m_playerStatHandler.m_isElementNull[i] = m_playerStatHandler.m_equippedEquipment[i] == null;
}
// 执行序列化
string json = JsonUtility.ToJson(m_saveData);

反序列化后恢复:

JsonUtility.FromJsonOverwrite(json, m_saveData);
for (int i = 0; i < m_playerStatHandler.m_equippedEquipment.Length; i++)
{
    if (m_playerStatHandler.m_isElementNull[i])
    {
        m_playerStatHandler.m_equippedEquipment[i] = null;
    }
}

2. 实现序列化回调接口自定义逻辑

通过ISerializationCallbackReceiver接口,在序列化前将null替换为带标记的占位实例,反序列化后再将占位实例转回null:

[Serializable]
public class Equipment
{
    public float statFloat;
    public int statInt;
    public bool statBool;
    [SerializeField] private bool _isNullPlaceholder; // 标记是否为占位实例

    // 给外部判断用的属性
    public bool IsNullPlaceholder => _isNullPlaceholder;
}

[Serializable]
public class PlayerStatHandler : ISerializationCallbackReceiver
{
    public Equipment[] m_equippedEquipment;

    public void OnBeforeSerialize()
    {
        if (m_equippedEquipment == null) return;
        for (int i = 0; i < m_equippedEquipment.Length; i++)
        {
            if (m_equippedEquipment[i] == null)
            {
                // 替换为占位实例
                m_equippedEquipment[i] = new Equipment { _isNullPlaceholder = true };
            }
        }
    }

    public void OnAfterDeserialize()
    {
        if (m_equippedEquipment == null) return;
        for (int i = 0; i < m_equippedEquipment.Length; i++)
        {
            if (m_equippedEquipment[i]?.IsNullPlaceholder == true)
            {
                // 恢复为null
                m_equippedEquipment[i] = null;
            }
        }
    }
}

之后直接使用JsonUtility.ToJson和FromJsonOverwrite即可,回调会自动处理空元素。

3. 改用第三方JSON库

如果不想做额外自定义逻辑,可以使用支持保留null数组元素的第三方库,比如Newtonsoft.Json(Unity官方提供适配版本):

// 序列化
string json = Newtonsoft.Json.JsonConvert.SerializeObject(m_saveData);
// 反序列化
SaveData loadedData = Newtonsoft.Json.JsonConvert.DeserializeObject<SaveData>(json);

该库会直接保留数组中的null元素,无需额外处理。

内容的提问来源于stack exchange,提问作者Michael Vann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:22:44