2012-05-18 23 views
7

Ben ProtoException olsun ("tespit Olası özyinelemeye (ofset: 4 seviyesi (ler)): EOW o") şöyle bir ağaç yapısı seri hale:serialize önek ağaç

var tree = new PrefixTree(); 
     tree.Add("racket".ToCharArray()); 
     tree.Add("rambo".ToCharArray()); 
     using (var stream = File.Open("test.prefix", FileMode.Create)) 
     { 
      Serializer.Serialize(stream, tree); 
     } 

ağaç uygulaması:

[ProtoContract] 
public class PrefixTree 
{ 
    public PrefixTree() 
    { 
     _nodes = new Dictionary<char, PrefixTree>(); 
    } 

    public PrefixTree(char[] chars, PrefixTree parent) 
    { 
     if (chars == null) throw new ArgumentNullException("chars"); 
     if (parent == null) throw new ArgumentNullException("parent"); 
     if (chars.Length == 0) throw new ArgumentException(); 

     _parent = parent; 
     _nodes = new Dictionary<char, PrefixTree>(); 
     _value = chars[0]; 

     var overflow = chars.SubSet(1); 
     if (!overflow.Any()) _endOfWord = true; 
     else Add(overflow.ToArray()); 
    } 

    [ProtoMember(1)] 
    private readonly char _value; 
    [ProtoMember(2)] 
    private readonly bool _endOfWord; 
    [ProtoMember(3)] 
    private readonly IDictionary<char, PrefixTree> _nodes; 
    [ProtoMember(4, AsReference = true)] 
    private readonly PrefixTree _parent; 

    public void Add(char[] word) 
    { 
     if (word == null) throw new ArgumentNullException("word"); 
     if (word.Length == 0) return; 

     var character = word[0]; 
     PrefixTree node; 
     if (_nodes.TryGetValue(character, out node)) 
     { 
      node.Add(word.SubSet(1)); 
     } 
     else 
     { 
      node = new PrefixTree(word, this); 
      _nodes.Add(character, node); 
     } 
    } 

    public override string ToString() 
    { 
     return _endOfWord ? _value + " EOW" : _value.ToString(); 
    } 
} 

public static class ListHelper 
{ 
    public static char[] SubSet(this char[] source, int start) 
    { 
     return source.SubSet(start, source.Length - start); 
    } 

    public static char[] SubSet(this char[] source, int start, int length) 
    { 
     if (start < 0) throw new ArgumentOutOfRangeException(); 
     if (start > source.Length) throw new ArgumentOutOfRangeException(); 
     if (length < 0) throw new ArgumentOutOfRangeException(); 

     var result = new char[length]; 
     Array.Copy(source, start, result, 0, length); 
     return result; 
    } 
} 

yanlış özelliklere sahip dekorasyon ya da ben sadece serileştirilemez ağaç tasarladık mıyım?

Düzenleme: boşuna bu çalıştı:

var typeModel = RuntimeTypeModel.Default; 
     var type = typeModel.Add(typeof(PrefixTree), false); 
     type.AsReferenceDefault = true; 
     type.Add("_value", "_endOfWord", "_nodes", "_parent"); 

     var tree = new PrefixTree(); 
     tree.Add("racket".ToCharArray()); 
     tree.Add("rambo".ToCharArray()); 
     using (var stream = File.Open("test.prefix", FileMode.Create)) 
     { 
      typeModel.Serialize(stream, tree); 
     } 
+0

'SubSet 'uzantı yönteminiz nedir? çalışan bir repro elde etmek için anlamak gerekir. Ayrıca; 'Add' yöntemi nedir? –

+0

Ancak! Buradaki temel sorun, "sözlük" işleyicisinin varsayılan olarak referans türlerini kullanmadığıdır. Çalışan bir repro elde edersem daha fazla bakabilirim. –

+0

Düzenleme, yine de "Hata Yöntem için aşırı yüklenme yok 'SubSet' 2 argüman alır" - ListHelper.SubSet yönteminde –

cevap

3

_parent ve Değer _nodes aynı tip (PrefixTree) her iki nokta, ama sadece _parent "AsReference" olarak işaretlenir.

Eğer seri hale yığını yürümek Eğer Sözlük değerin Değer bağımsız _parent öğenin tefrika ve yinelenen bir örneği için işaretli olmadığından emin göreceksiniz.

buna çift dağıtımları tespit başladığı 25 dahili seri derinlik kontrolü, orada ağaç yürür gibi. Bu değer daha büyük olsaydı, bir istisna alamazdı, eğer daha küçükse, ağacın üstündeki bir düğüme atıyordu.

Ben de bu deserializable olacağını düşünüyorum ve yok her çocuk düğümün _ana alanın değeri _nodes konteyner ile aynı örneği olmayacağını did kesinlikle eğer.

Sen kendi sözlüğü tipisin (alt sınıf Sözlük <,> ya,> IDictionary < uygulamak) oluşturmanız gerekir böylece [ProtoContract] özelliğini ekledi ve Sözlüğün öğelerin seri kontrol edebilirsiniz.

[ProtoContract] 
public class NodeItem 
{ 
    [ProtoMember(1)] 
    public char Key { get; set; } 
    [ProtoMember(2, AsReference = true)] 
    public PrefixTree Value { get; set; } 
} 

[ProtoContract] 
public class Nodes : IDictionary<char, PrefixTree> 
{ 
    private readonly IDictionary<char, PrefixTree> inner; 

    [ProtoMember(1)] 
    public NodeItem[] Items 
    { 
     get 
     { 
      return this.inner.Select(item => new NodeItem() {Key = item.Key, Value = item.Value}).ToArray(); 
     } 
     set 
     { 
      foreach(NodeItem item in value) 
      { 
       this.inner.Add(item.Key, item.Value); 
      } 
     } 
    } 
    ... // Omitted IDictionary members for clarity 

yani Burada anahtar düğümlerin en PrefixTree bağlı AsReference meta elde etmektir. Ayrıca, Öğelerin bir Diziyi döndürdüğünü de unutmayın, bir liste olarak istiyorsanız, OverwriteList öznitelik üyesini kullanmanız gerekir.

Ben de PrefixTree tipinde her alan için salt okunur anahtar kelimeyi kaldırmak için gerekli. Bu birim testi benim için geçti.

 [TestMethod] 
    public void TestMethod1() 
    { 
     var tree = new PrefixTree(); 
     tree.Add("racket".ToCharArray()); 
     tree.Add("rambo".ToCharArray()); 

     PrefixTree tree2 = null; 

     using (var stream = new MemoryStream()) 
     { 
      Serializer.Serialize(stream, tree); 
      stream.Position = 0; 
      tree2 = Serializer.Deserialize<PrefixTree>(stream); 
     } 


     Assert.IsNotNull(tree2); 
     Assert.AreEqual(tree._nodes.Count, tree2._nodes.Count); 
     Assert.AreEqual(2, tree2._nodes['r']._nodes['a']._nodes.Count);  // 'c' and 'm' 
     Assert.AreEqual('c', tree2._nodes['r']._nodes['a']._nodes.Values.First().Value); 
     Assert.AreEqual('m', tree2._nodes['r']._nodes['a']._nodes.Values.Last().Value); 
    }