2012-06-21 5 views
1

protobuf.net을 사용하여 개체를 serialize하는 데 문제가 있습니다. 저는 다른 클래스에서이 클래스를 사용했지만 매우 잘 작동하지만 사용하지는 않습니다.Proto-Buf.Net 및 serialization

왜 그런지 말해 주실 수 있습니까? 감사.

BinaryFormatter가 serialize/deserializing에서 매우 느리기 때문에 protobuf를 사용하고 싶습니다.

using System.Collections.Generic; 
using System; 
using ProtoBuf; 
using System.Xml.Serialization; 
using System.Runtime.Serialization; 

namespace RadixTree 
{ 
[Serializable, DataContract, ProtoContract] 
public class Node<T> 
{ 
    private readonly List<Node<T>> children = new List<Node<T>>(); 
    private readonly string key; 
    private T value; 
    public Node(string key, T value) 
    { 
     this.key = key; 
     this.value = value; 
    } 
    private Node() 
    { 
    } 
    protected bool HasChildren 
    { 
     get { return children.Count > 0; } 
    } 
    public void Insert(string key, T value) 
    { 
     var potentialChild = new Node<T>(key, value); 
     Add(potentialChild); 
    } 
    private bool Add(Node<T> theNewChild) 
    { 
     if (Contains(theNewChild)) 
      throw new DuplicateKeyException(string.Format("Duplicate key: '{0}'", theNewChild.key)); 

     if (!IsParentOf(theNewChild)) 
      return false; 

     bool childrenObligedRequest = RequestChildrenToOwn(theNewChild); 
     if (childrenObligedRequest) return true; 

     AcceptAsOwnChild(theNewChild); 
     return true; 
    } 
    private bool RequestChildrenToOwn(Node<T> newChild) 
    { 
     return 
      children.Exists(
       existingChild => 
       existingChild.MergeIfSameAs(newChild) || existingChild.Add(newChild) || 
       ForkANewChildAndAddChildren(existingChild, newChild)); 
    } 
    private bool MergeIfSameAs(Node<T> potentialChild) 
    { 
     if (!IsTheSameAs(potentialChild) || IsNotUnrealNode()) 
      return false; 

     value = potentialChild.value; 
     return true; 
    } 
    private bool IsNotUnrealNode() 
    { 
     return !IsUnrealNode(); 
    } 
    private void Disown(Node<T> existingChild) 
    { 
     children.Remove(existingChild); 
    } 
    private Node<T> AcceptAsOwnChild(Node<T> child) 
    { 
     if (NotItself(child)) children.Add(child); 
     return this; 
    } 
    private bool NotItself(Node<T> child) 
    { 
     return !Equals(child); 
    } 
    private bool ForkANewChildAndAddChildren(Node<T> existingChild, Node<T> newChild) 
    { 
     if (existingChild.IsNotMySibling(newChild)) 
      return false; 

     var surrogateParent = MakeASurrogateParent(existingChild, newChild); 
     if (surrogateParent.IsTheSameAs(this)) 
      return false; 

     SwapChildren(existingChild, newChild, surrogateParent); 
     return true; 
    } 
    private bool IsNotMySibling(Node<T> newChild) 
    { 
     return !IsMySibling(newChild); 
    } 
    private void SwapChildren(Node<T> existingChild, Node<T> newChild, Node<T> surrogateParent) 
    { 
     surrogateParent.AcceptAsOwnChild(existingChild) 
      .AcceptAsOwnChild(newChild); 

     AcceptAsOwnChild(surrogateParent); 
     Disown(existingChild); 
    } 
    private Node<T> MakeASurrogateParent(Node<T> existingChild, Node<T> newChild) 
    { 
     string keyForNewParent = existingChild.CommonBeginningInKeys(newChild); 
     keyForNewParent = keyForNewParent.Trim(); 
     var surrogateParent = new Node<T>(keyForNewParent, default(T)); 

     return surrogateParent.IsTheSameAs(newChild) ? newChild : surrogateParent; 
    } 
    private bool IsTheSameAs(Node<T> parent) 
    { 
     return Equals(parent); 
    } 
    private bool IsMySibling(Node<T> potentialSibling) 
    { 
     return CommonBeginningInKeys(potentialSibling).Length > 0; 
    } 
    private string CommonBeginningInKeys(Node<T> potentialSibling) 
    { 
     return key.CommonBeginningWith(potentialSibling.key); 
    } 
    internal virtual bool IsParentOf(Node<T> potentialChild) 
    { 
     return potentialChild.key.StartsWith(key); 
    } 
    public bool Delete(string key) 
    { 
     Node<T> nodeToBeDeleted = children.Find(child => child.Find(key) != null); 
     if (nodeToBeDeleted == null) return false; 

     if (nodeToBeDeleted.HasChildren) 
     { 
      nodeToBeDeleted.MarkAsUnreal(); 
      return true; 
     } 

     children.Remove(nodeToBeDeleted); 
     return true; 
    } 
    private void MarkAsUnreal() 
    { 
     value = default(T); 
    } 
    public T Find(string key) 
    { 
     var childBeingSearchedFor = new Node<T>(key, default(T)); 
     return Find(childBeingSearchedFor); 
    } 
    private T Find(Node<T> childBeingSearchedFor) 
    { 
     if (Equals(childBeingSearchedFor)) return value; 
     T node = default(T); 
     children.Find(child => 
          { 
           node = child.Find(childBeingSearchedFor); 
           return node != null; 
          }); 
     if (node == null) return default(T); 
     return node; 
    } 
    public bool Contains(string key) 
    { 
     return Contains(new Node<T>(key, default(T))); 
    } 
    private bool Contains(Node<T> child) 
    { 
     if (Equals(child) && IsUnrealNode()) return false; 

     if (Equals(child)) return true; 

     return children.Exists(node => node.Contains(child)); 
    } 
    private bool IsUnrealNode() 
    { 
     return value == null; 
    } 
    public List<T> Search(string keyPrefix) 
    { 
     var nodeBeingSearchedFor = new Node<T>(keyPrefix, default(T)); 
     return Search(nodeBeingSearchedFor); 
    } 
    private List<T> Search(Node<T> nodeBeingSearchedFor) 
    { 
     if (IsTheSameAs(nodeBeingSearchedFor)) 
      return MeAndMyDescendants(); 

     return SearchInMyChildren(nodeBeingSearchedFor); 
    } 
    private List<T> SearchInMyChildren(Node<T> nodeBeingSearchedFor) 
    { 
     List<T> searchResults = null; 

     children.Exists(existingChild => (searchResults = existingChild.SearchUpAndDown(nodeBeingSearchedFor)).Count > 0); 

     return searchResults; 
    } 
    private List<T> SearchUpAndDown(Node<T> node) 
    { 
     if (node.IsParentOf(this)) 
      return MeAndMyDescendants(); 

     return IsParentOf(node) ? Search(node) : new List<T>(); 

    } 
    private List<T> MeAndMyDescendants() 
    { 
     var meAndMyDescendants = new List<T>(); 
     if (!IsUnrealNode()) 
      meAndMyDescendants.Add(value); 

     children.ForEach(child => meAndMyDescendants.AddRange(child.MeAndMyDescendants())); 
     return meAndMyDescendants; 
    } 
    public long Size() 
    { 
     const long size = 0; 
     return Size(size); 
    } 
    private long Size(long size) 
    { 
     if (!IsUnrealNode()) 
      size++; 

     children.ForEach(node => size += node.Size()); 
     return size; 
    } 
    public override string ToString() 
    { 
     return key; 
    } 
    public bool Equals(Node<T> other) 
    { 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 
     return Equals(other.key, key); 
    } 
    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) return false; 
     if (ReferenceEquals(this, obj)) return true; 
     if (obj.GetType() != typeof (Node<T>)) return false; 
     return Equals((Node<T>) obj); 
    } 
    public override int GetHashCode() 
    { 
     return (key != null ? key.GetHashCode() : 0); 
    } 
    public static Node<T> Root() 
    { 
     return new RootNode<T>(); 
    } 
    public List<Node<T>> getChildren() 
    { 
     return children; 
    } 
    [Serializable, DataContract, ProtoContract] 
    private class RootNode<T> : Node<T> 
    { 
     public RootNode() { } 
     internal override bool IsParentOf(Node<T> potentialChild) 
     { 
      return true; 
     } 
    } 

} 
} 

답변

1

protobuf - 그물, DataContractSerializerXmlSerializer 등 같은 것들과 함께이 단순히 필드에서 작동하지 않기 때문에 :

는 클래스입니다. 그것은 정보 어떤 필드에 대한 직렬화 및 식별 방법 (비록 거기에 암시 적 옵션입니다, 나는 그것을 권장하지 않음). 예 :

[ProtoMember(3)] private readonly List<Node<T>> children = new List<Node<T>>(); 
[ProtoMember(1)] private readonly string key; 
[ProtoMember(2)] private T value; 

그러면 잘 작동합니다.

(직렬화하는 회원 나타내는 다른 방법이있다 - 속성이 바로 가장 편리한은, 당신의 유형은 또한 [DataContract]로 표시되기 때문에 정보를 원하시면, 동일, [DataMember(Order=n)] 작업 것)


나를 위해

다음 작품 잘 :

[Test] 
public void Main() 
{ 
    Node<int> tree = new Node<int>("abc", 1), clone; 
    var children = tree.getChildren(); 
    children.Add(new Node<int>("abc/def", 2)); 
    children.Add(new Node<int>("abc/ghi", 3)); 
    Assert.AreEqual(2, tree.getChildren().Count); 

    using(var ms = new MemoryStream()) 
    { 
     Serializer.Serialize(ms, tree); 
     Assert.Greater(1, 0); // I always get these args the wrong way around, 
     Assert.Greater(ms.Length, 0); // so I always double-check! 
     ms.Position = 0; 
     clone = Serializer.Deserialize<Node<int>>(ms); 
    } 

    Assert.AreEqual("abc", clone.Key); 
    Assert.AreEqual(1, clone.Value); 
    children = clone.getChildren(); 
    Assert.AreEqual(2, children.Count); 

    Assert.IsFalse(children[0].HasChildren); 
    Assert.AreEqual("abc/def", children[0].Key); 
    Assert.AreEqual(2, children[0].Value); 

    Assert.IsFalse(children[1].HasChildren); 
    Assert.AreEqual("abc/ghi", children[1].Key); 
    Assert.AreEqual(3, children[1].Value); 
} 

편집 다음 프로젝트 예 :

첫째로 RootNode<T>은 실제로는 RootNode이어야합니다. 중첩 된 유형은 이미 포함 된 유형의 T을 상속합니다. 이 관계가 선언 될 필요가 있음을 맞았지만, C# 컴파일러는 속성의 제네릭에 대한 사랑이 없습니다 -

첫째, RootNode의 문제가있다 :

여기에 두 가지 문제가 있습니다. 솔직히 말해서 을 상속하지 않고 캡슐화한다고 말할 수 있습니다. 당신이 상속해야하는 경우, 그것은 고통이고, 당신은, 런타임에 즉

RuntimeTypeModel.Default.Add(typeof(Node<MyDto>), true) 
    .AddSubType(4, typeof(Node<MyDto>.RootNode)); 

두 번째 문제가 중첩 된 목록/배열을 선언 할 것이다; childrenList<List<YourType>>이됩니다. 현재 시간에, 그 시나리오 내가 조금 혼란 스러워요 있지만 예외를 제기하지 않은 이유, 지원되지 않습니다 - 그것은 NotSupportedException가 인용 던져을 의미한다 :

중첩 또는 들쭉날쭉 목록 및 배열은 지원되지 않습니다.

나는 그것이 왜 발생시키지 않는지 조사 할 것입니다!

여기에있는 문제는 중간에 메시지가 없으면 (예 : 내 컨트롤 외부의) protobuf 사양이 이러한 데이터를 나타내는 방법이 없다는 것입니다.

[ProtoContract] 
class SomeNewType { 
    [ProtoMember(1)] 
    public List<MyDto> Items {get {return items;}} 
    private readonly List<MyDto> items = new List<MyDto>(); 
} 

Node<SomeNewType>보다는 Node<List<MyDto>> 사용합니다. 이론에서

, protobuf - 그물 그 층이 중간에 있었다 척, 그냥 어쨌든에 수행 할 수 - 단순히 : I/쓰기를 설계하는 시간이 없었어요/그렇게하는 데 필요한 코드를 테스트 아직.

+0

안녕하세요 저는 ProtoMember를 사용하려고했지만 작동하지 않습니다. 나는 무엇을해야할지 모른다. BinaryFormatter가 너무 느리기 때문에 protobuf를 사용하고 싶습니다. 당신이 나를 도울 수? 감사합니다 – Mapo

+0

나는 또한 trie DataMember를 추가했지만 작동하지 않습니다. 묵시적 옵션을 사용하는 방법을 말해 줄 수 있습니까? – Mapo

+0

나는 [ProtoContract (ImplicitFields = ImplicitFields.AllFields)] 코드도 사용했다. 결과가 없습니다. 파일 크기는 항상 0kb입니다! :( – Mapo