2015-11-04 92 views
0

我試圖將數據序列化到/從我的類派生的MonoBehaviour,這不能從客戶端代碼創建(例如,與new關鍵字),而是必須由Unity3D專用方法創建,GameObject.AddComponent<T>()。如何使用YamlDotNet框架來爲我的類填充值而無需爲每個類創建適配器?是否有某種可以配置的內置適配器,這樣YamlDotNet就不會實例化它想要序列化的類了嗎?Unity3D&YamlDotNet將數據反序列化爲Monobehaviour派生類

典型的文件可能包含項目的映射,例如,

%YAML 1.1 
%TAG !invt! _PathwaysEngine.Inventory. 
%TAG !intf! _PathwaysEngine.Adventure. 
--- 

Backpack_01: !invt!Item+yml 
    mass: 2 
    desc: 
    nouns: /^bag|(back)?pack|sack|container$/ 
    description: | 
     Your backpack is only slightly worn, and... 
    rand_descriptions: 
    - "It's flaps twirl in the breeze." 
    - "You stare at it. You feel enriched." 

MagLite_LR05: !invt!Lamp+yml 
    cost: 56 
    mass: 2 
    time: 5760 
    desc: 
    nouns: /^light|flashlight|maglite|lr_05$/ 
    description: | 
     On the side of this flashlight is a label... 

     (Type "light" to turn it on and off.) 

... 

當標籤是我的項目的完全指定類的名稱,例如,PathwaysEngine.Inventory.Lamp+ymlPathwaysEngine是我用我的遊戲引擎命名空間代碼,Inventory處理項目& whatnot和Lamp+yml是編譯器如何表示嵌套類ymlLampLamp+yml可能是這樣的:

public partial class Lamp : Item, IWearable { 
    public new class yml : Item.yml { 
     public float time {get;set;} 
     public void Deserialize(Lamp o) { 
      base.Deserialize((Item) o); 
      o.time = time; 
     } 
    } 
} 

我打電話Deserialize()上派生從ThingAwake()所有對象,即,一旦在遊戲中存在MonoBehaviour類。在其他地方,我已經創建了一個非常複雜的Dictionary,其中填充了Someclass+yml類型的對象,然後Deserialize接收實際運行時類Someclass的一個實例,並用值填充它。有一個更清潔的方式來做到這一點,對吧?

如何我:

  1. 告訴Deserializer什麼我的教室在哪裏? 請參閱第二次編輯以獲得上述問題的良好解決方案

  2. 獲取沒有它的數據試圖創建我的MonoBehaviour派生類?

編輯:我因爲工作的問題,並發現了與自定義數據處理(在我試圖解析正則表達式我的數據的具體情況的一個很好的方式,並讓他們不被視爲字符串&因此,不可轉換爲正則表達式)是對該特定字符串使用IYamlTypeConverter。然而,使用YamlDotNet和Unity3D MonoBehaviour仍然是一個問題。

另一編輯:上面的例子使用一種非常難看的方式來確定類型。以我爲例,做的最好的事情是與解串器,如先註冊標記,

var pre = "tag:yaml.org,2002:"; 
var tags = new Dictionary<string,Type> { 
    { "regex", typeof(Regex) }, 
    { "date", typeof(DateTime) }, 
    { "item", typeof(Item) }}; 
foreach (var tag in tags) 
    deserializer.RegisterTagMapping(
     pre+tag.Key, tag.Value); 

然後,我用的是!!tag符號在*.yml文件,例如,

%YAML 1.1 
--- 

Special Item: !!item 
    nouns: /thing|item|object/ 
    someBoolean: true 

Start Date: !!date 2015-12-17 

some regex: !!regex /matches\s+whatever/ 

... 
+0

通常序列化框架有一些自定義的方法來初始化的東西。我從來沒有用過yaml,但是如果沒有辦法解決這個問題,最好的辦法可能就是使用MonoBehaviour作爲另一個類的包裝。 你只序列內類,然後設置的MonoBehaviour自己 – Luz

+0

啊,這基本上就是我與嵌套'yml'類做的事情。 –

回答

1

你可以將IObjectFactory的自定義實現傳遞給Deserializer類的構造函數。每當解串器需要創建一個對象實例時,它將使用IObjectFactory來創建它。

請注意,您的工廠將負責創建的實例,每個類型都是反序列化的。實現它的最簡單的方法是創建一個裝飾圍繞DefaultObjectFactory,如:

class UnityObjectFactory : IObjectFactory 
{ 
    private readonly DefaultObjectFactory DefaultFactory = 
     new DefaultObjectFactory(); 

    public object Create(Type type) 
    { 
     // You can use specific types manually 
     if (type == typeof(MyCustomType)) 
     { 
      return GameObject.AddComponent<MyCustomType>(); 
     } 
     // Or use a marker interface 
     else if (typeof(IMyMarkerInterface).IsAssignableFrom(type)) 
     { 
      return typeof(GameObject) 
       .GetMethod("AddComponent") 
       .MakeGenericMethod(type) 
       .Invoke(); 
     } 
     // Delegate unknown types to the default factory 
     else 
     { 
      return DefaultFactory(type); 
     } 
    } 
} 
+0

儘管這很有幫助,但我的問題是我想將我的項目和項目放在編輯器中,所以它們已經存在於場景中,我的類已經添加爲組件。這可能會讓我使用的黑客必需。 無論如何,這可能對人們有幫助,我可能只是接受這個答案並修改我的問題,詢問另一個如果我不知道,等等。 感謝您的幫助,無論哪種方式! –

相關問題