2012-02-19 69 views
3

我有这个代码递归问题:递归例外

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.IO; 
using ProtoBuf; 

namespace ConsoleApplication4 
{ 
[Serializable] 
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)] 
public class GeneralWrapper<T> where T : new() 
{ 
    public GeneralWrapper() 
    { 
     Datas = new T(); 
    } 

    public T Datas { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<Document> _documents = new List<Document>(); 

     for (int i = 0; i < 100000; i++) 
     { 
      Document _document = new Document() 
      { 
       DocumentName = "asdadsf" 
      }; 

      _documents.Add(_document); 
     } 

     BinaryFormatter _formatter = new BinaryFormatter(); 

     FileStream fs = new FileStream 
      ("Person1.bin", FileMode.OpenOrCreate); 

     ProtoBuf.Serializer.Serialize(fs, _documents); 

     fs.Close(); 

     // Deserialize. 
     fs = new FileStream 
      ("Person1.bin", FileMode.OpenOrCreate); 

     List<Document> _document22 = ProtoBuf.Serializer.Deserialize<List<Document>>(fs); 

     fs.Close(); 
    } 
} 

[ProtoContract] 
public class Document 
{ 
    public Document() 
    { 
     _count = 234234924; 

     Section = new Section(); 

     Section.SectionName = "sdfasd"; 
    } 

    [ProtoMember(1)] 
    public string DocumentName { get; set; } 

    [ProtoMember(2)] 
    Dictionary<string, List<string>> Hello { get; set; } 
    [ProtoMember(3, AsReference=true)] 
    public Section Section { get; set; } 

    [ProtoMember(4)] 
    private string _sectionName; 
    [ProtoMember(5)] 
    public string SectionName 
    { 
     get 
     { 
      return Section.SectionName; 
     } 

     set 
     { 
      _sectionName = value; 

      Section.SectionName = _sectionName; 
     } 
    } 

    public int _count; 
    public int Count 
    { 
     get 
     { 
      return _count; 
     } 
    } 
} 

[Serializable] 
[ProtoContract] 
public class Section 
{ 
    public Section() 
    { 
     Section1 = new SectionInner(this); 

     Hellos = new List<GeneralWrapper<List<string>>>(); 

     GeneralWrapper<List<string>> _hello = new GeneralWrapper<List<string>>(); 

     _hello.Datas.Add("hello"); 

     Hellos.Add(_hello); 

     DHello = new Dictionary<string, List<Section>>(); 

     if (!DHello.ContainsKey("asdf")) 
     { 
      List<Section> _dhello1 = new List<Section>(); 

      _dhello1.Add(this); 

      DHello.Add("asdf", _dhello1); 
     } 
    } 

    [ProtoMember(1, AsReference=true)] 
    public SectionInner Section1 { get; set; } 
    [ProtoMember(2)] 
    public string SectionName { get; set; } 

    [ProtoMember(3, AsReference=true)] 
    public Dictionary<string, List<Section>> DHello { get; set; } 

    List<GeneralWrapper<List<string>>> Hellos { get; set; } 
} 

[Serializable] 
[ProtoContract] 
public class SectionInner 
{ 
    public SectionInner(Section section) 
    { 
     Section = section; 
    } 

    [ProtoMember(1, AsReference=true)] 
    public Section Section { get; set; } 
} 

}

我明明做的代码非常递归到开始,因为这是我真实的项目正在做同样的事情。这个问题似乎是这样的:

Dictionary<string, List<Section>> 

没事的时候被加入到这个字典中,一切都序列化的罚款。如果使用某个键将列表添加到字典中,则会发生递归。

是在支持这个代码/语法protobuf网?:

Dictionary<string, List<Section>> 

我需要把列出目录中的外部包装类,如:

Dictionary<string, Wrapper<List<Section>>> 

感谢您的帮助。我是protobuf-net的新手。

回答

2

首先 - 我必须注意,在构造器中执行那么多设置不是一个好主意。如果这代表您的实际代码,则您可能想在反序列化期间跳过构造函数([ProtoContract(SkipConstructor=true)])。如果它只是说明,很好。

是的,类似字典和列表的东西都支持,但是* 直接嵌套列表不是 - 所以List<List<...>>目前不好。你可能会用Dictionary<TKey,List<...>>避开它,因为它的键值对已经充当中间的包装。

重递归:protobuf-net支持很多递归场景,但是这是扩展的正式规范。因此,您需要明确地启用它,并注意:这种情况下交互并不容易,因为没有正式的规范说明;但是:[ProtoMember(n, AsReference=true)]可以在单个成员上启用对象跟踪。请注意,所有使用此对象的地方都必须标记为这样,否则它们将使用树序列化。

Re“为什么不直接支持递归” - 因为:protobuf(正式规范)的表现与大多数序列化器相似,并且是序列化器。注意:像XmlSerializer,JavascriptSerializer和DataContractSerializer(默认模式)的东西是也是树序列化器,并且如果给定递归结构将爆炸。这个是正常的。 protobuf-net在一些情况下不会采用这种方式,但是默认情况下不能启用它,因为它需要不同的数据布局,从而破坏了跨平台数据规范的目的。

如果我错过了你的任何问题,请说。

+0

为什么我的代码违反[ProtoMember(3,IsReference = true)] public Dictionary > DHello {get;组; }当我试图添加一个键值对。它会到达值中的每个部分,一旦到达该部分,它就会再次返回到该部分的DHello,并再次返回到该部分,并且正在递归。我在两个地方都放了[ProtoMember(x,AsReference = true)],但它仍然说有递归?谢谢你的帮助。 – iefpw 2012-02-19 08:48:49

+0

@iefpw我现在不在PC上,所以我可以使用心理调试......但是:keyvaluepair不会**应用“IsReference”,所以我认为它来自那里(带有包含“this”的列表)。也许一个包装可以让你添加这个。另一个选项(之前已经提到)是为我添加一个类型级别的“始终将此视为参考”选项,**补充**成员级配置。 – 2012-02-19 08:56:52