2011-11-01 12 views
5

Marb GravellによってC#のprotobufで既存のシリアライザを置き換えようとしています。私のコードは大規模で、私の目標は最小限の変更でスイッチを実行できることです。protobuf-netで「同じキーを持つアイテムが既に追加されています」というエラーが発生しました

私は、なぜそれが起こるのか理解していると信じていましたが、克服するための助けを必要としました。特に、既存のコードとクラスの変更を最小限に抑えるソリューションが必要でした。私のコードは複雑ですので、私は問題を証明するために、次の短いサンプルを作成しました:親オブジェクトが作成されると、要するに

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がデシリアライズ時にオブジェクトを再構築しようとすると、同じコンストラクタを使用して(値付き辞書を開始する)、デシリアライズ - >エラーの一環として同じ値を再度プッシュしようとします。

コードの変更を最小限に抑えて、どのように克服できますか?

親切に、 ヨッシー。ここ

+0

マイナーノート: "protobuf-net"は単なる実装です。他のC#protobuf実装があります。なぜ私はタイトルを変更したのかを説明するためにこれを言います –

答えて

5

最も簡単なオプションは、おそらくです:

、それが言うように、コンストラクタ(またはフィールド初期化子)を実行しません
[ProtoContract(SkipConstructor = true)] 

。データがない場合、これは辞書をnullのままにします。別のアプローチは、(それがデータをロードされる直前に発射)シリアライゼーション・コールバックを使用することがあります

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

第三の選択肢は、使用して上記を組み合わせることであろう。

[ProtoContract(SkipConstructor = true)] 

と:

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

デフォルトでは、データがなくても空の辞書になります。これはデフォルトのSonコンストラクタを使用するので、Fatherからもこれを行う必要があります。

+0

ありがとう、マーク。私はあなたの提案を試み、彼らは私の問題を解決します。私は第3の選択肢(最低限のリソースが要求される)に行くと信じています。ヨッシー。 – yossic

関連する問題