You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity Json.Net反序列化报错:无法为TestData设置textAssetRef值

解决Unity中Newtonsoft.Json反序列化自定义资源引用的报错问题

我之前在做Unity资源引用序列化的时候也踩过完全一样的坑,你遇到的报错核心是:Newtonsoft.Json不知道如何将序列化后的JSON转换回你的TextAssetRef类型,导致赋值到TestDatatextAssetRef字段时失败。下面给你一步步的解决方案:

首先,先补全你没写完的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);
    }
}

最后再排查几个容易踩的坑:

  • 确保TestDataTextAssetRef都标记了[Serializable]特性
  • 如果你之前的TextAssetRef没有无参构造函数,一定要加上——这是反序列化实例化对象的基础
  • 运行时的资源加载逻辑要适配你的项目(比如用Addressables还是Resources),上面的示例里Editor用了AssetDatabase,运行时需要换成对应的加载方式

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

火山引擎 最新活动