2011-11-01 12 views
5

Tôi đang cố gắng thay thế trình nối tiếp hiện có với protobuf cho C# của Marc Gravell. Mã của tôi mở rộng và mục tiêu của tôi là có thể thực hiện chuyển đổi với những thay đổi tối thiểu.Lỗi "Một mục có cùng khóa đã được thêm vào" với protobuf-net

Tôi gặp một vấn đề mà tôi tin rằng tôi hiểu tại sao nó xảy ra nhưng yêu cầu trợ giúp khắc phục - đặc biệt là giải pháp yêu cầu ít thay đổi nhất trong mã và lớp hiện có của tôi. Mã của tôi rất phức tạp vì vậy tôi đã tạo ra mẫu ngắn sau đây để chứng minh vấn đề:

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); 
      } 

     } 
    } 

} 
} 

Nói tóm lại, khi đối tượng cha mẹ được tạo ra, nó tạo ra một đối tượng con trai mà trong tệp một cuốn từ điển với một số giá trị. Tôi giả sử rằng khi protobuf cố gắng xây dựng lại đối tượng khi deserializing nó sử dụng cùng một constructor (do đó cũng khởi tạo từ điển với các giá trị) và sau đó cố gắng đẩy các giá trị giống như một phần của lỗi deserializing ->.

Làm cách nào để khắc phục sự cố với những thay đổi tối thiểu đối với mã của tôi?

Trân trọng, Yossi.

+0

Ghi chú nhỏ: "protobuf-net" chỉ là một triển khai; có các triển khai protobuf C# khác. Tôi chỉ đề cập đến điều này để giải thích tại sao tôi thay đổi tiêu đề –

Trả lời

5

Các tùy chọn dễ dàng nhất ở đây có lẽ là:

[ProtoContract(SkipConstructor = true)] 

mà sẽ, như nó nói, không thực hiện các nhà xây dựng (hoặc trường-initializers). Lưu ý rằng điều này sẽ để trống từ điển nếu không có dữ liệu. Một cách khác có thể sử dụng một callback serialization (mà cháy ngay trước khi nó được nạp với dữ liệu):

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

Một lựa chọn thứ ba sẽ được kết hợp trên bằng cách sử dụng:

[ProtoContract(SkipConstructor = true)] 

và:

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

để đặt mặc định thành từ điển trống ngay cả khi không có dữ liệu. Lưu ý rằng bạn cũng cần phải thực hiện điều này từ Father vì điều đó sử dụng hàm tạo mặc định Son.

+0

Cảm ơn rất nhiều, Marc. Tôi đã thử đề xuất của bạn và họ giải quyết vấn đề của tôi. Tôi tin rằng tôi sẽ đi với tùy chọn thứ 3 (ít yêu cầu tài nguyên nhất). Yossi. – yossic