fastJSON反序列化列表
本文关键字:列表 反序列化 fastJSON | 更新日期: 2023-09-27 18:29:46
所以这是在我之前的问题的基础上构建的。我正在尝试保存一个蓝图,它只是一堆游戏对象/实体的设置。我现在将组件(及其设置)存储为List<IEntityComponent>(IEntityComponent是任何组件的接口)封装在名为ComponentTable的类中。我只想序列化列表,所有的私有内容都没有序列化,只是为了更快地查找(以内存为代价)。这可以正确地序列化,甚至可以反序列化而没有任何错误,但我注意到componentTable没有正确地反序列化。
它创建了ComponentTable的一个实例,但从未实际向其添加值。因此,它只是一个空的ComponentTable,而不是一个包含CameraComponent、VelocityComponent和InputComponent的Component表。
{
"$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和colors的序列化/序列化,因为任何单位值类型都会导致错误。
我相信它的序列化是正确的,但由于某种原因,它没有反序列化到componentTable中。有人知道fastJSON在这种继承方面是否有问题吗(使类从List<customClass>继承?
理想情况下,我会让它作为Dictionary<类型,IEntityComponent>,但fastJSON不会序列化该类型,只是将其保存为"System.Mono",然后在序列化时导致错误。
编辑:这里是蓝图和组件表类
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上测试了一下,发现了以下问题:
-
fastJSON不会反序列化
Components
属性,除非它有一个公共setter:public sealed class Blueprint { public ComponentTable Components { get; set; }
似乎没有任何配置选项可以解决这个问题。从
Reflection.cs
可以看到创建setter委托的方法,如果setter不是公共的,则返回null
:internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo) { MethodInfo setMethod = propertyInfo.GetSetMethod(); if (setMethod == null) return null;
-
fastJSON似乎确实无法反序列化
List<T>
的子类——或任何其他非数组集合类——不是泛型。在反序列化程序中有以下检查:if (pi.IsGenericType && pi.IsValueType == false && v is List<object>) oset = CreateGenericList((List<object>)v, pi.pt, pi.bt, globaltypes);
正如您所看到的,它检查目标类型是否为泛型,而不是目标类型或其基类型之一是否为泛型。
你可以通过使你的
ComponentTable
通用化来解决这个问题: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; }
并且列表内容将被反序列化。然而
-
您的
ComponentTable
继承自List<T>
,需要重写Add()
。但是Add()
不是虚拟的,所以您使用的是public new Add()
。这里的问题是,如果有人将你的类强制转换为List<T>
并调用Add()
,你的方法就不会被调用。特别是,fastJSON在反序列化过程中不会调用它!因此,在反序列化过程中,您的类型字典从未初始化过,这违背了目的。看起来你正在做的是重新发明
KeyedByTypeCollection<TItem>
。使用这个类,ComponentTable
变得非常简单: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上进行序列化和反序列化,而不会出现数据损坏。但是。。。
-
我不确定
KeyedByTypeCollection<TItem>
是否统一存在。如果没有,您可能需要对其进行移植。请参阅引用源KeyedByTypeCollection.cs
和基类源keyedcollection.cs
。可以在这里找到一种尝试:Mono.Net.中KeyedByTypeCollection的替代方案 -
或者,您可以考虑使用Json.NET。Json.NET支持通过
TypeNameHandling
设置序列化多态类型。但是,它在团结上可用吗?谷歌建议有一些统一的端口。这里还有各种各样的问题,用Json.NET和unity3d标记,例如匿名对象的Json.NET Unity反序列化字典。所以,你可以进一步研究这个选项。