fastJSON反序列化列表 [英] fastJSON Deserialization List

查看:98
本文介绍了fastJSON反序列化列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我先前提出的问题的基础.我正在尝试保存蓝图,这只是游戏对象/实体的一堆设置.我现在将这些组件(及其设置)存储为列表<包装在称为ComponentTable的类中的IEntityComponent>(IEntityComponent是任何组件的接口).我只想序列化列表,而所有私有的东西都不序列化,只是为了更快地查找(以内存为代价).这样可以正确地序列化甚至进行反序列化,而不会出现任何错误,但是我注意到componentTable没有正确地反序列化.

So sort of a build on from a previous question of mine. I am trying to save a blueprint, which is just a heap of settings for a gameobject/Entity. I'm now storing the components (And their settings) as a List < IEntityComponent > (IEntityComponent is the interface for any component) wrapped in a class called ComponentTable. I only want to serialize the list, and all the private stuff is not serialized, and is just for faster look ups (At the price of memory). This serializes properly and even deserializes without any errors, but i noticed the componentTable isn't deserializing PROPERLY.

它创建ComponentTable的实例,但从不实际向其中添加值.因此,它不是包含CameraComponent,VelocityComponent和InputComponent的Component表,而只是一个空的ComponentTable.

It creates an instance of ComponentTable, but never actually adds the values to it. So instead of a Component table containing CameraComponent, VelocityComponent and InputComponent, it just just an empty ComponentTable.

{
 "$types" : {
  "ECS.Framework.Collections.Blueprint, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" : "1",
  "ECS.Features.Core.CameraComponent, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" : "2",
  "ECS.Features.Core.VelocityComponent, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" : "3",
  "InputComponent, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" : "4"
 },
 "$type" : "1",
 "Components" : [
  {
     "$type" : "2",
     "Tag" : "MainCamera",
     "Test" : "0, 0, 0",
     "BackgroundColour" : "0, 0, 1, 1",
     "ViewportRect" : "10, 10 : 10, 10",
     "Orthographic" : false,
     "FieldOfView" : 60,
     "OrthoSize" : 5,
     "Depth" : 0,
     "OcclusionCulling" : true,
     "HDR" : false,
     "Enabled" : true
  },
  {
     "$type" : "3",
     "Enabled" : true,
     "CurrentVelocity" : "0, 0, 0"
  },
  {
     "$type" : "4",
     "TEST" : 0,
     "Enabled" : true
  }
 ],
 "Children" : [

 ],
 "Parent" : ""
}

这是保存方式,因此似乎保存正确.我只控制Vectors,Rect和颜色的序列化/序列化,因为任何单位值类型都会导致错误.

This is how it saves, so it seems like it is saving correctly. I am only controlling the serialization/serialization of the Vectors, Rect and colors, as any unity value types cause errors.

我相信它可以正确地序列化,但是由于某种原因,它没有反序列化到componentTable中.有谁知道fastJSON是否存在这种继承问题(使类从List< customClass>继承?

I believe it is serializing properly, but for some reason it is not deserializing into the componentTable. Does anyone know if fastJSON has problems with this kind of inheritance (Making a class inherit from a List< customClass >?

理想情况下,我希望它继承为Dictionary<类型,IEntityComponent>,但是fastJSON不会序列化类型,只是将其保存为"System.Mono",然后在序列化时导致错误.

Ideally i would have it inherit as a Dictionary< Type, IEntityComponent >, but fastJSON wont serialize the Type, just saves it as 'System.Mono' then causes an error when serializing.

这是蓝图和组件表类

public sealed class Blueprint 
{
    public ComponentTable Components { get; private set; }

    public List<string> Children { get; set; }

    public string Parent { get; set; }

    public Blueprint()
    {
        Components = new ComponentTable();

        Children = new List<string>();
        Parent = "";
    }

    public Blueprint(Blueprint _blueprint)
    {
        Children = new List<string>(_blueprint.Children);

        Parent = _blueprint.Parent;
    }
}


public class ComponentTable : List<IEntityComponent>
{
    private Dictionary<Type, IEntityComponent> Components { get; set; }

    #region Constructors

    public ComponentTable()
    {
        Components = new Dictionary<Type, IEntityComponent>();
    }

    #endregion

    #region Base Function Overrides

    public void Add(Type _type)
    {
        if (Components.ContainsKey(_type))
            return;

        InternalAdd(_type, (IEntityComponent)Activator.CreateInstance(_type));
    }
    public new void Add(IEntityComponent _component)
    {
        InternalAdd(_component.GetType(), _component);
    }
    public void Add<T>() where T : IEntityComponent
    {
        Add(typeof(T));
    }
    private void InternalAdd(Type _type, IEntityComponent _component)
    {
        if (Components.ContainsKey(_type))
            throw new InvalidOperationException("Component already contained");

        Components.Add(_type, _component);
        base.Add(_component);
    }

    public bool Remove(Type _type)
    {
        if (Components.ContainsKey(_type))
            return InternalRemove(_type, Components[_type]);
        return false;
    }
    public new bool Remove(IEntityComponent _component)
    {
        return InternalRemove(_component.GetType(), _component);
    }
    public bool Remove<T>() where T : IEntityComponent
    {
        return Remove(typeof(T));
    }
    private bool InternalRemove(Type _type, IEntityComponent _component)
    {
        if (!Components.ContainsKey(_type))
            return false;

        Components.Remove(_type);
        return base.Remove(_component);
    }

    public IEntityComponent Get(Type _type)
    {
        if (Contains(_type))
            return Components[_type];
        return null;
    }
    public T Get<T>() where T : IEntityComponent
    {
        return (T)Get(typeof(T));
    }

    public bool TryGetValue(Type _type, out IEntityComponent _component)
    {
        return Components.TryGetValue(_type, out _component);
    }
    public bool TryGetValue<T>(out IEntityComponent _component) where T : IEntityComponent
    {
        return TryGetValue(typeof(T), out _component);
    }

    public bool Contains(Type _type)
    {
        return Components.ContainsKey(_type);
    }
    public new bool Contains(IEntityComponent _component)
    {
        return Contains(_component.GetType());
    }
    public bool Contains<T>() where T : IEntityComponent
    {
        return Contains(typeof(T));
    }

    #endregion

}

推荐答案

我在Microsoft .Net上进行了一些测试,发现了以下问题:

I tested this a bit on Microsoft .Net, and found the following issues:

  1. fastJSON 不会反序列化Components属性,除非它具有公共设置器:

  1. fastJSON will not deserialize the Components property unless it has a public setter:

public sealed class Blueprint 
{
    public ComponentTable Components { get; set; }

似乎没有任何配置选项可以解决此问题.在 Reflection.cs 中,您可以看到创建设置器的方法如果设置器不是公共的,则委托返回null:

There doesn't appear to be any sort of configuration option to work around this. From Reflection.cs you can see the method to create the setter delegate returns null if the setter is not public:

internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo)
{
    MethodInfo setMethod = propertyInfo.GetSetMethod();
    if (setMethod == null)
        return null;

  • fastJSON确实似乎无法反序列化List<T>的子类-或任何其他非数组集合类-不是通用的.在解串器中,进行以下检查:

  • fastJSON does indeed appear to be unable to deserialize a subclass of List<T> -- or any other non-array collection class -- that is not generic. Inside the deserializer there is the following check:

    if (pi.IsGenericType && pi.IsValueType == false && v is List<object>)
        oset = CreateGenericList((List<object>)v, pi.pt, pi.bt, globaltypes);
    

    如您所见,它将检查目标类型是否为通用类型,而不是目标类型或其基本类型之一是否为通用类型.

    As you can see, it checks for the target type being generic, rather than the target type or one of its base types being generic.

    您可以通过使您的ComponentTable具有通用性来解决此问题:

    You could work around this by making your ComponentTable be generic:

    public class ComponentTable<TEntityComponent> : List<TEntityComponent> where TEntityComponent : IEntityComponent
    {
        private Dictionary<Type, TEntityComponent> Components { get; set; }
    
        #region Constructors
    
        public ComponentTable()
        {
            Components = new Dictionary<Type, TEntityComponent>();
        }
    
        #endregion
    
        #region Base Function Overrides
    
        public void Add(Type _type)
        {
            if (Components.ContainsKey(_type))
                return;
    
            InternalAdd(_type, (TEntityComponent)Activator.CreateInstance(_type));
        }
        public new void Add(TEntityComponent _component)
        {
            InternalAdd(_component.GetType(), _component);
        }
        public void Add<T>() where T : IEntityComponent
        {
            Add(typeof(T));
        }
        private void InternalAdd(Type _type, TEntityComponent _component)
        {
            if (Components.ContainsKey(_type))
                throw new InvalidOperationException("Component already contained");
    
            Components.Add(_type, _component);
            base.Add(_component);
        }
    
        public bool Remove(Type _type)
        {
            if (Components.ContainsKey(_type))
                return InternalRemove(_type, Components[_type]);
            return false;
        }
        public new bool Remove(TEntityComponent _component)
        {
            return InternalRemove(_component.GetType(), _component);
        }
        public bool Remove<T>() where T : IEntityComponent
        {
            return Remove(typeof(T));
        }
        private bool InternalRemove(Type _type, TEntityComponent _component)
        {
            if (!Components.ContainsKey(_type))
                return false;
    
            Components.Remove(_type);
            return base.Remove(_component);
        }
    
        public IEntityComponent Get(Type _type)
        {
            if (Contains(_type))
                return Components[_type];
            return null;
        }
        public T Get<T>() where T : IEntityComponent
        {
            return (T)Get(typeof(T));
        }
    
        public bool TryGetValue(Type _type, out TEntityComponent _component)
        {
            return Components.TryGetValue(_type, out _component);
        }
        public bool TryGetValue<T>(out TEntityComponent _component) where T : IEntityComponent
        {
            return TryGetValue(typeof(T), out _component);
        }
    
        public bool Contains(Type _type)
        {
            return Components.ContainsKey(_type);
        }
        public new bool Contains(TEntityComponent _component)
        {
            return Contains(_component.GetType());
        }
        public bool Contains<T>() where T : IEntityComponent
        {
            return Contains(typeof(T));
        }
    
        #endregion
    }
    

    然后将Blueprint更改为:

    public sealed class Blueprint
    {
        public ComponentTable<IEntityComponent> Components { get; set; }
    

    并且列表内容将被反序列化.但是...

    And the list contents will be deserialized. However...

    您的ComponentTable是从List<T>继承的,需要覆盖Add().但是Add()不是虚拟的,因此您使用的是public new Add().这里的问题是,如果有人将您的类强制转换为List<T>并调用Add(),则不会调用您的方法.特别是,fastJSON在反序列化期间不会调用它!因此,您的类型字典永远不会在反序列化期间初始化,从而无法达到目的.

    Your ComponentTable is inheriting from List<T> and needs to override Add(). But Add() is not virtual, and so you are using public new Add() instead. The problem here is that if anybody casts your class to a List<T> and calls Add(), your method won't get called. In particular, fastJSON will not call it during deserialization! So your type dictionary is never initialized during deserialization, defeating the purpose.

    您正在做的事情是重新发明

    What it appears you are doing is re-inventing KeyedByTypeCollection<TItem>. Rather than do that, you can just use it. Using this class, your ComponentTable becomes very simple:

    public class ComponentTable<TEntityComponent> : KeyedByTypeCollection<TEntityComponent> where TEntityComponent : IEntityComponent
    {
        public void Add(Type _type)
        {
            if (Contains(_type))
                return;
            Add((TEntityComponent)Activator.CreateInstance(_type));
        }
    
        public void Add<T>() where T : IEntityComponent, new()
        {
            Add(typeof(T));
        }
    }
    

    现在,可以在Microsoft .Net上对集合进行序列化和反序列化,而不会造成数据损坏.但是...

    Now the collection can be serialized and deserialized with no data corruption on Microsoft .Net. However...

    我不确定KeyedByTypeCollection<TItem>是否存在统一.如果没有,您可能需要移植它.请参见参考源 KeyedByTypeCollection.cs 和基类源 keyedcollection.cs .可以在这里找到一种尝试: Alternative NET中的KeyedByTypeCollection .

    I'm not sure that KeyedByTypeCollection<TItem> exists in unity. If not, you may need to port it. See the reference source KeyedByTypeCollection.cs and the base class source keyedcollection.cs. One attempt to do it can be found here: Alternative to KeyedByTypeCollection in Mono .Net.

    作为替代方案,您可以考虑使用Json.NET. Json.NET支持通过 TypeNameHandling设置序列化多态类型.但是,它可以统一使用吗?

    As an alternative, you might consider using Json.NET. Json.NET supports serializing polymorphic types via the TypeNameHandling setting. But, is it available on unity?

    Google建议存在一些统一的端口.在标记有Json.NET和unity3d 的地方,还有很多问题,例如 JSON .Net Unity反序列化匿名对象字典.因此,您可能会进一步研究该选项.

    Google suggests that there are some ports for unity. There are also a variety of questions here tagged with both Json.NET and unity3d, for instance JSON .Net Unity Deserialize dictionary of anonymous objects. So, you might investigate that option further.

    这篇关于fastJSON反序列化列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆