首页 文章

如何将类的JSON序列化重定向到另一个类?

提问于
浏览
1

我有一种情况,我需要将任何 GameObject 序列化为内部的其他东西( GameObjectMetadata ),其中包含有助于以后再次反序列化的数据 .

public struct GameObjectMetadata
{
    public string AssetFullPath;
    public string AssetBundle;
    public string GUID;
    public string UnityType;
}

public struct TestPrefabLink
{
    public GameObject Prefab;
}

我真的很难实现实现这一目标所需的JSON.NET转换器 . 我已经有一段时间了,并提出了以下代码 . 它主要工作,但我收到以下错误:

JsonSerializationException:反序列化对象时出现意外的标记:EndObject . Path'Component . $ values [0]',第14行,第7位.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(Newtonsoft.Json.JsonReader reader,System.Type objectType,Newtonsoft.Json.Serialization.JsonContract contract,Newtonsoft . Json.Serialization.JsonProperty成员,Newtonsoft.Json.Serialization.JsonContainerContract containerContract,Newtonsoft.Json.Serialization.JsonProperty containerMember,System.Object existingValue)(at C:/Development/Releases/Json/Working/Newtonsoft.Json/Working-Signed /Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:336)

串行:

data = JsonConvert.SerializeObject(blueprint, Formatting.Indented,
            new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All,
                NullValueHandling = NullValueHandling.Include,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                Converters = new List<JsonConverter>() { new GameObjectMetadataJsonConverter(), new UnityObjectJsonConverter() }
            });

使用的转换器:

public class GameObjectMetadataJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {       
        var jobj = JObject.FromObject(value);
        jobj.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var metadata = serializer.Deserialize<GameObjectMetadata>(reader);

        // Snipped - Code here successfully converts to GameObject
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (GameObjectMetadata);
    }
}

public class UnityObjectJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(UnityEngine.Object).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return existingValue; // This should not be called. But it is??
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var metadata = new GameObjectMetadata();
        metadata.UnityType = value.GetType().ToString();

        var path = UnityEditor.AssetDatabase.GetAssetPath((UnityEngine.Object)value);
        var bundleName = UnityEditor.AssetImporter.GetAtPath(path).assetBundleName;
        var guid = UnityEditor.AssetDatabase.AssetPathToGUID(path);

        metadata.AssetBundle = bundleName;
        metadata.AssetFullPath = path;
        metadata.GUID = guid;

        //var jobj = JObject.FromObject(metadata);
        //jobj.WriteTo(writer);
        serializer.Serialize(writer, metadata);
    }
}

似乎我在这里做的任何事情都会导致一些糟糕的JSON写出来 . 但我无法弄清楚如何从预期的结构/类中写出不同的结构/类 .

1 回答

  • 1

    确实会调用UnityObjectJsonConverter.ReadJson(),因为在反序列化期间,将调用CanConvert(objectType),其中要反序列化的预期类型不是序列化到文件的实际类型 . 预期的类型将是 UnityEngine.Object 的某个子类型 .

    因此,您需要执行以下操作:

    public struct GameObjectMetadata
    {
        public GameObjectMetadata(UnityEngine.Object value)
        {
            if (value == null)
                throw new ArgumentNullException();
    
            this.UnityType = value.GetType();
    
            var path = UnityEditor.AssetDatabase.GetAssetPath(value);
            var bundleName = UnityEditor.AssetImporter.GetAtPath(path).assetBundleName;
            var guid = UnityEditor.AssetDatabase.AssetPathToGUID(path);
    
            this.AssetBundle = bundleName;
            this.AssetFullPath = path;
            this.GUID = guid;
        }
    
        public UnityEngine.Object GetRealObject()
        {
            // I'm not a unity3d developer so I am not sure this is the correct method to call.
            return UnityEditor.AssetDatabase.LoadAssetAtPath(AssetFullPath, UnityType);
        }
    
        public string AssetFullPath;
        public string AssetBundle;
        public string GUID;
        public Type UnityType;
    }
    
    public class UnityObjectJsonConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(UnityEngine.Object).IsAssignableFrom(objectType);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var metadata = serializer.Deserialize<GameObjectMetadata>(reader);
            return metadata.GetRealObject();
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            // WriteJson is never called when value == null.  Instead Json.NET calls writer.WriteNull() directly.
            var metadata = new GameObjectMetadata((UnityEngine.Object)value);
            serializer.Serialize(writer, metadata);
        }
    }
    

    没有必要 GameObjectMetadataJsonConverter .

    注意我不是unity3d开发人员所以我不确定AssetDatabase.LoadAssetAtPath(AssetFullPath, Type.GetType(UnityType))是调用从其元数据重建游戏对象的正确方法,所以用任何正确的替换 .

相关问题