为何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
相关产品推荐
相关产品推荐

