这是我之前问题的基础。我正在尝试保存一个蓝图,它只是游戏对象/实体的一堆设置。我现在将组件(及其设置)存储为列表 < IEntityComponent > (IEntityComponent 是任何组件的接口(interface)),包装在名为 ComponentTable 的类中。我只想序列化列表,所有私有(private)内容都没有序列化,只是为了更快的查找(以内存为代价)。这可以正确序列化,甚至反序列化没有任何错误,但我注意到 componentTable 没有正确反序列化。
它创建了 ComponentTable 的一个实例,但从未实际向其中添加值。因此,它不是包含 CameraComponent、VelocityComponent 和 InputComponent 的 Component 表,而是一个空的 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" : ""
}
这就是它的保存方式,所以看起来它保存正确。我只控制向量、矩形和颜色的序列化/序列化,因为任何统一值类型都会导致错误。
我相信它正在正确序列化,但由于某种原因它没有反序列化到组件表中。有谁知道fastJSON是否有这种继承的问题(Making a class继承自List
理想情况下,我会将其继承为 Dictionary< Type, 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
属性,除非它有公共(public) setter :public sealed class Blueprint { public ComponentTable Components { get; set; }
似乎没有任何配置选项可以解决此问题。来自
Reflection.cs
您可以看到创建 setter 委托(delegate)的方法返回null
如果 setter 不公开:internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo) { MethodInfo setMethod = propertyInfo.GetSetMethod(); if (setMethod == null) return null;
fastJSON 确实似乎无法反序列化
List<T>
的子类- 或任何其他非数组集合类 - 不是通用的。里面deserializer有以下检查: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
。可以在这里找到一种尝试: Alternative to KeyedByTypeCollection in Mono .Net .作为替代方案,您可以考虑使用 Json.NET。 Json.NET 通过
TypeNameHandling
setting 支持序列化多态类型。但是,它可以在 Unity 上使用吗?Google suggests有一些统一的端口。这里还有各种各样的问题tagged with both Json.NET and unity3d ,例如JSON .Net Unity Deserialize dictionary of anonymous objects 。因此,您可以进一步研究该选项。
关于c# - fastJSON 反序列化列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34707871/