2016-01-10 75 views
1

從我以前的一個問題開始構建。我正在嘗試保存一個藍圖,這只是一堆遊戲對象/實體的設置。我現在將組件(和它們的設置)作爲列表存儲在一個名爲ComponentTable的類中,IEntityComponent>(IEntityComponent是任何組件的接口)。我只想序列化這個列表,並且所有私有的東西都不是序列化的,只是爲了加快查找速度(以內存爲代價)。這序列化正確,甚至反序列化沒有任何錯誤,但我注意到componentTable不正確反序列化。fastJSON反序列化列表

它創建一個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" : "" 
} 

這是它如何保存,所以它看起來好像是正確保存。我只控制向量,矩形和顏色的序列化/序列化,因爲任何單值類型都會導致錯誤。

我相信它是正確的序列化,但由於某種原因它不是反序列化到componentTable中。有誰知道,如果FASTJSON有問題,這種繼承的(從列表中製作一個類繼承< customClass>?

理想我想有繼承它作爲一個字典<類型,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 

} 

回答

0

我測試這一點上微軟的.Net藍圖和組件表類,並發現以下問題:

  1. fastJSON不會反序列化Components財產,除非它有一個公共的二傳手:

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

    雖然目前沒有出現任何類型的配置選項來解決這個問題。從Reflection.cs你可以看到方法來創建二傳手委託返回null如果setter方法是不公開的:

    internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo) 
    { 
        MethodInfo setMethod = propertyInfo.GetSetMethod(); 
        if (setMethod == null) 
         return null; 
    
  2. 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; } 
    

    ,榜單內容將被反序列化。然而...

  3. ComponentTableList<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)); 
        } 
    } 
    

    現在集合可以被序列化,並與微軟的.Net沒有數據損壞反序列化。然而...

  4. 我不確定KeyedByTypeCollection<TItem>是否存在統一。如果不是,您可能需要將其移植。請參閱參考源KeyedByTypeCollection.cs和基類源keyedcollection.cs。試圖做到這一點可以在這裏找到:Alternative to KeyedByTypeCollection in Mono .Net

  5. 作爲替代方案,您可以考慮使用Json.NET。 Json.NET支持通過TypeNameHandling setting序列化多態類型。但是,它是否可以統一?

    Google suggests表示有一些端口用於統一。這裏還有各種各樣的問題tagged with both Json.NET and unity3d,例如JSON .Net Unity Deserialize dictionary of anonymous objects。所以,你可能會進一步調查這個選項。

+0

嚴重頂級回答10/10。你把比我想象的更多的細節放在那裏,非常感謝你。我沒有意識到類KeyedByTypeCollection甚至存在,我會嘗試改變它,看看它如何與fastJSON一起工作。我假設你嘗試使用fastJSON序列化它,它的工作?老實說,我可以使用不同的JSON,即使fastJSON不是統一的一部分,我不得不導入它,它恰好是我發現的第一個。加上它看起來很快,並有很多功能。但它仍然遇到像這樣的問題,所以我可能會改變它在 – Lolop

+0

@Lolop - 我成功地在Microsoft.Net上成功使用fastJSON成功使'KeyedByTypeCollection '成功。我沒有團結,所以我無法在那裏測試。 – dbc

+0

你是上帝派的。我確實必須將這些類複製到一個統一體中,並修復那些與統一體無關的東西。唯一的問題是他們用來拋出錯誤,我不得不用他們的替換(希望不是我的損失),只是正常的例外。這是因爲(我假設)統一使用.Net 3.5,而他們在KeyedByType中使用的東西,它的基類是.Net 4.5+? (也可能是爲什麼它不是一致的開始)。再次感謝你,我可能永遠不會想到它。私人環境正在停止反序列化,但通用的東西正在打破它。 – Lolop