自定义Json.net转换器失效:反序列化GameObject类型不兼容报错排查
由于GameObject无法被直接序列化,我编写了GameObjectReferencer类存储GameObject名称,试图反序列化时通过名称查找对象,但出现以下错误:
JsonSerializationException: Type specified in JSON 'GameObjectReferencer, SaveSystem, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with 'UnityEngine.GameObject, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. Path 'wrappedSaveDatas.$values[4].savedObject.other.$type', line 338, position 55.
自定义转换器代码
public class GameObjectFromReferenceConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(GameObjectReferencer); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new Exception("GameObjectFromReferenceConverter should only be used when loading"); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { GameObjectReferencer goRef = (GameObjectReferencer)reader.Value; return ((GameObjectReferencer)goRef).GetGameObject(); } }
GameObjectReferencer类代码
public class GameObjectReferencer { public string targetGameObjectName; public GameObjectReferencer(string gameObjectName) { this.targetGameObjectName = gameObjectName; } public GameObject GetGameObject() { GameObject go = GameObject.Find(targetGameObjectName); if (go == null) throw new System.Exception("Can't find object with the name " + targetGameObjectName); return go; } public override string ToString() { return "GameObjectReference of \"" + targetGameObjectName+ "\""; } public static GameObjectReferencer GenerateReference(GameObject gameObject) { return new GameObjectReferencer(gameObject.name); } }
问题分析与修复方案
核心问题
错误根源在于:
- 转换器的
CanConvert仅针对GameObjectReferencer类型,但反序列化的目标字段是GameObject,导致转换器未被触发 ReadJson中直接将reader.Value强转为GameObjectReferencer是错误的,reader.Value是JSON原始数据,并非已实例化的GameObjectReferencer对象GameObjectReferencer缺少无参构造函数,Json.NET无法自动反序列化该类
修复步骤
1. 调整转换器的目标类型
让转换器处理GameObject类型,因为我们需要把JSON中的GameObjectReferencer数据转换为GameObject:
public override bool CanConvert(Type objectType) { return objectType == typeof(GameObject); }
2. 正确反序列化GameObjectReferencer并获取GameObject
修改ReadJson方法,先将JSON数据反序列化为GameObjectReferencer实例,再调用方法获取对应GameObject:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var goRef = serializer.Deserialize<GameObjectReferencer>(reader); return goRef?.GetGameObject(); }
3. 给GameObjectReferencer添加无参构造函数
Json.NET需要无参构造函数才能完成反序列化:
public class GameObjectReferencer { public string targetGameObjectName; // 添加无参构造函数 public GameObjectReferencer() { } public GameObjectReferencer(string gameObjectName) { this.targetGameObjectName = gameObjectName; } // 其他原有代码不变 }
4. 完善序列化逻辑(可选)
如果需要将GameObject序列化为GameObjectReferencer数据,补充WriteJson方法:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var go = (GameObject)value; var goRef = GameObjectReferencer.GenerateReference(go); serializer.Serialize(writer, goRef); }
5. 注册转换器到序列化配置
确保序列化/反序列化时使用该转换器:
var settings = new JsonSerializerSettings(); settings.Converters.Add(new GameObjectFromReferenceConverter()); // 序列化 string saveJson = JsonConvert.SerializeObject(yourSaveDataObject, settings); // 反序列化 var loadedData = JsonConvert.DeserializeObject<YourSaveDataType>(saveJson, settings);
内容的提问来源于stack exchange,提问作者WVrock

