2011-02-28 57 views
2

我嘗試用各種對象(int,bool,list,dictionary等)構建二叉樹並序列化/反序列化它。protobuf-net的通用樹的序列化

用二進制formmater序列化它很好,但與protobufnet我有錯誤。

我不知道問題是與樹的暗示或使用protobuf網。

任何回答將幫助我
感謝

編輯

我嘗試了兩種版本的樹的代碼,我在網上

第一版發現 Tree data structure in C#

Seconed版本 http://msdn.microsoft.com/en-us/library/ms379572.aspx

兩個版本中的T是對象。

,我得到了錯誤: 沒有合適的默認對象編碼找到

+1

有什麼錯誤?這棵樹看起來像什麼?樂意幫忙,但是有點模糊...... –

+0

我編輯了q。我還有一個錯誤,但我不記得是哪一個。謝謝 – david

+0

作爲參考,如果你包括@marc,那麼我會自動得到一些東西告訴我你已經回覆。我不需要補充一點,因爲我正在回覆您的*帖子*。我只提到它的原因是我只是看到了這一點,記得回頭看看。現在看... –

回答

2

要系列化與protobuf的,有關於如何將成員映射了一些必要的數據 - 並注意每個成員本身必須是有意義的protobuf,或者必須是某種列表。

如果你能證明你正在使用我可以幫助更多確切的樹,但例如:

[ProtoContract] 
    class Node<T> 
    { 
     [ProtoMember(1)] 
     public T Value { get; set; } 
     [ProtoMember(2, DataFormat= DataFormat.Group)] 
     public List<Node<T>> Children { get { return children; } } 
     private readonly List<Node<T>> children = new List<Node<T>>(); 
    } 

應該序列罰款。必要的數據也可以在運行時以「v2」提供。


部分基於電子郵件對話的一部分,我理解模型好一點,我看到了重要的變化是:

  • 值字段必須標註的系列化
  • 類必須註釋
  • 必須有一個無參數構造函數
  • 必須有一些它用來添加和枚舉子列表

最後是一個有趣的;我作出了故意的決定,不要求在那裏需要完整的IList/IList<T> - 它需要的全部是IEnumerable<T>Add(T)方法,所以我可以添加一個私有包裝對象,該對象僅存在用於序列化的目的。

因此,基於郵件內容:

using System; 
using System.Collections.Generic; 
using ProtoBuf; 


static class Program 
{ 
    static void Main() 
    { 
     var tree = new NTree<int>(1); 
     tree.addChild(2); 
     var child = tree.addChild(3); 
     tree.addChild(4); 
     child.addChild(5); 
     child.addChild(6).addChild(7); 


     var clone = Serializer.DeepClone(tree); 
     DrawTree(tree); 
     Console.WriteLine(); 
     Console.WriteLine(); 
     DrawTree(clone); 
    } 
    static void DrawTree<T>(NTree<T> tree, int depth = 0) 
    { 
     var prefix = new string('\t', depth++); 
     Console.WriteLine(prefix + tree.Data); 
     foreach (var child in tree.Children) DrawTree(child, depth); 
    } 
} 

[ProtoContract] 
class NTree<T> 
{ 
    [ProtoMember(1)] 
    T data; 
    LinkedList<NTree<T>> children; 
    internal T Data { get { return data; } } // added for demo only 
    internal IEnumerable<NTree<T>> Children { get { return children; } }// added for demo only 
    public NTree(T data) 
    { 
     this.data = data; 
     children = new LinkedList<NTree<T>>(); 
    } 

    public NTree<T> addChild(T data) // changed just so I can build a tree for the demo 
    { 
     var child = new NTree<T>(data); 
     children.AddFirst(child); 
     return child; 
    } 

    public NTree<T> getChild(int i) 
    { 
     foreach (NTree<T> n in children) 
      if (--i == 0) return n; 
     return null; 
    } 

    private NTree() 
    { 
     children = new LinkedList<NTree<T>>(); 
    } 

    [ProtoMember(2, DataFormat=DataFormat.Group)] 
    private NodeWrapper WrappedChildren { 
     get { return new NodeWrapper(children); } 
    } 
    private class NodeWrapper:IEnumerable<NTree<T>> 
    { // only exists to help with serialization 
     private readonly LinkedList<NTree<T>> nodes; 

     public NodeWrapper(LinkedList<NTree<T>> nodes) 
     { 
      this.nodes = nodes; 
     } 
     public IEnumerator<NTree<T>> GetEnumerator() 
     { 
      return nodes.GetEnumerator(); 
     } 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
     { 
      return nodes.GetEnumerator(); 
     } 
     public void Add(NTree<T> child) { nodes.AddLast(child); } 
    } 
} 

應該爲大多數你在它扔,除了objectT工作。任何不尋常的對象本身都可能是數據合同。

爲V2

注:

  • 你不需要的屬性;可所有在運行時
  • 指定你不需要參數的構造函數(儘管它可能是最簡單的,以保持一個,使children啓動容易)
  • 列表可以是不通用的,IEnumerableAdd(object)(但預期類型必須指定)
+0

謝謝!只是看到它,我會稍後再嘗試。 – david

+0

感謝您的詳細解答。有沒有什麼改變,將V2中的Dicionary 添加到樹中是合法的? – david

+0

@marc你說:_notes for v2:你不需要屬性;這些都可以在runtime_指定。你能告訴我如何在節點上添加RuntimeTypeModel,當我不知道T嗎?節點或節點很明顯。 –