2011-11-01 86 views
5

我想用Marc Gravell的C#protobuf替换现有的序列化程序。我的代码非常广泛,我的目标是能够以最少的更改完成切换。“一个项目具有相同的密钥已被添加”与protobuf网错误

我遇到了一个问题,我相信我明白了为什么会发生这种情况,但需要帮助克服 - 尤其是需要对现有代码和类进行最少更改的解决方案。我的代码是复杂的,所以我创建了以下简短的示例来演示该问题:

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


namespace ConsoleApplication1 
{ 
    class program_issue 
    { 

    [ProtoContract] 
    public class Father 
    { 
     public Father() 
     { 
      sonny = new Son(); 
     } 

     [ProtoMember(101)] 
     public string Name; 

     [ProtoMember(102)] 
     public Son sonny; 

    } 

    [ProtoContract] 
    public class Son 
    { 
     public Son() 
     { 
      Dict.Add(10, "ten"); 
     } 

     [ProtoMember(103)] 
     public Dictionary<int, string> Dict = new Dictionary<int, string>(); 
    } 


    static void Main(string[] args) 
    { 
     Father f1 = new Father(); 
     f1.Name = "Hello"; 
     byte[] bts = PBSerializer.Serialize(typeof(Father), f1); 

     Father f2; 
     PBSerializer.Deserialize(bts, out f2); 

    } 


    public static class PBSerializer 
    { 
     public static byte[] Serialize(Type objType, object obj) 
     { 
      MemoryStream stream = new MemoryStream(); 
      ProtoBuf.Serializer.Serialize(stream, obj); 
      string s = Convert.ToBase64String(stream.ToArray()); 
      byte[] bytes = stream.ToArray(); 
      return bytes; 
     } 


     public static void Deserialize(byte[] data, out Father obj) 
     { 
      using (MemoryStream stream = new MemoryStream(data)) 
      { 
       obj = ProtoBuf.Serializer.Deserialize<Father>(stream); 
      } 

     } 
    } 

} 
} 

总之,在创建父对象时,它创建inits一些值的字典子对象。我认为,当protobuf在反序列化时试图重建对象时,它使用相同的构造函数(因此也启动带有值的字典),然后尝试再次推送相同的值作为反序列化 - >错误的一部分。

如何通过对代码进行最少更改来克服它?

亲切的问候, Yossi。

+0

小调:“protobuf-net”只是一个实现;还有其他C#protobuf实现。我只是提到这个来解释为什么我改变了标题 –

回答

5

这里最简单的方法可能是:

[ProtoContract(SkipConstructor = true)] 

将,因为它说,不执行构造函数(或现场初始化)。请注意,如果没有数据,这将使字典为空。另一种方法可能是使用一个序列化回调(之前它被加载数据的时候触发):

[ProtoBeforeDeserialization] 
private void Foo() 
{ 
    Dict.Clear(); 
} 

第三个选项是将上述通过结合:

[ProtoContract(SkipConstructor = true)] 

和:

[ProtoAfterDeserialization] 
private void Foo() 
{ 
    if(Dict == null) Dict = new Dictionary<int,string>(); 
} 

默认它为一个空字典,即使没有数据。请注意,您也需要从Father开始,因为它使用默认的Son构造函数。

+0

非常感谢,Marc。我尝试了你的建议,他们解决了我的问题。我相信我会选择第三种方式(资源要求最低)。贝纳。 – yossic

相关问题