Unity Json.Net反序列化报错:无法为TestData设置textAssetRef值
解决Unity中Newtonsoft.Json反序列化自定义资源引用的报错问题
我之前在做Unity资源引用序列化的时候也踩过完全一样的坑,你遇到的报错核心是:Newtonsoft.Json不知道如何将序列化后的JSON转换回你的TextAssetRef类型,导致赋值到TestData的textAssetRef字段时失败。下面给你一步步的解决方案:
首先,先补全你没写完的TextAssetRef类(这类自定义资源引用通常会存资源的GUID,然后在需要时加载),必须确保它有无参构造函数——这是Newtonsoft.Json反序列化的关键,否则框架无法创建实例:
[Serializable] public class TextAssetRef { // 序列化存储的资源GUID public string guid; // 运行时加载的资源对象,不序列化 [NonSerialized] public TextAsset asset; // 无参构造函数,反序列化必须要有 public TextAssetRef() {} // 方便在Editor中初始化的构造函数 public TextAssetRef(TextAsset targetAsset) { asset = targetAsset; #if UNITY_EDITOR guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(asset)); #endif } }
接下来,核心问题是反序列化时,Newtonsoft.Json不知道如何根据JSON里的GUID加载对应的TextAsset,所以我们需要写一个自定义Json转换器来处理这个逻辑:
public class TextAssetRefConverter : JsonConverter<TextAssetRef> { public override TextAssetRef ReadJson(JsonReader reader, Type objectType, TextAssetRef existingValue, bool hasExistingValue, JsonSerializer serializer) { // 读取JSON对象 JObject jsonObj = JObject.Load(reader); string resourceGuid = jsonObj["guid"].Value<string>(); // 创建TextAssetRef实例 var assetRef = new TextAssetRef(); assetRef.guid = resourceGuid; // 根据GUID加载资源,区分Editor和运行时环境 #if UNITY_EDITOR string assetPath = AssetDatabase.GUIDToAssetPath(resourceGuid); assetRef.asset = AssetDatabase.LoadAssetAtPath<TextAsset>(assetPath); #else // 运行时建议用Addressables或者Resources加载,这里给个Addressables的示例 // assetRef.asset = Addressables.LoadAssetAsync<TextAsset>(resourceGuid).WaitForCompletion(); // 如果用Resources,需要确保资源在Resources文件夹下,且手动处理GUID转Resources路径 #endif return assetRef; } public override void WriteJson(JsonWriter writer, TextAssetRef value, JsonSerializer serializer) { // 序列化时只写入GUID,因为asset是不序列化的 JObject jsonObj = new JObject(); jsonObj.Add("guid", value.guid); jsonObj.WriteTo(writer); } }
然后有两种方式让Newtonsoft.Json使用这个转换器:
方式一:给TextAssetRef类添加特性
直接在TextAssetRef类上标记转换器,这样序列化反序列化时会自动使用:
[Serializable] [JsonConverter(typeof(TextAssetRefConverter))] // 加上这行特性 public class TextAssetRef { // ... 之前的代码 }
方式二:在序列化反序列化时传入转换器设置
如果不想修改TextAssetRef类,可以在调用JsonConvert时传入自定义设置:
public void Awake() { try { var settings = new JsonSerializerSettings(); settings.Converters.Add(new TextAssetRefConverter()); // 添加转换器 var sData = JsonConvert.SerializeObject(testData, Formatting.Indented, settings); UnityEngine.Debug.Log(sData); testData = JsonConvert.DeserializeObject<TestData>(sData, settings); UnityEngine.Debug.Log("Done."); } catch (Exception x) { UnityEngine.Debug.LogError(x.Message); } }
最后再排查几个容易踩的坑:
- 确保
TestData和TextAssetRef都标记了[Serializable]特性 - 如果你之前的
TextAssetRef没有无参构造函数,一定要加上——这是反序列化实例化对象的基础 - 运行时的资源加载逻辑要适配你的项目(比如用Addressables还是Resources),上面的示例里Editor用了
AssetDatabase,运行时需要换成对应的加载方式
内容的提问来源于stack exchange,提问作者v3nz




