2011-11-01 14 views
5

sto cercando di sostituire un serializzatore esistente con protobuf per C# da Marc Gravell. Il mio codice è esteso e il mio obiettivo è essere in grado di fare lo switch con modifiche minime."è già stato aggiunto un elemento con la stessa chiave" errore protobuf-net

Mi sono imbattuto in un problema che credo di capire perché accade ma richiede un aiuto per il superamento - in particolare una soluzione che richiederebbe il minimo cambiamento nel mio codice e nelle classi già esistenti. Il mio codice è complesso così ho creato il seguente breve esempio per dimostrare il problema:

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

     } 
    } 

} 
} 

In breve, quando si crea l'oggetto padre, si crea un oggetto figlio che INITs un dizionario con alcuni valori. Suppongo che quando protobuf cerca di ricostruire l'oggetto quando deserializzazione utilizza lo stesso costruttore (iniziando così anche il dizionario con i valori) e poi cerca di spingere di nuovo gli stessi valori come parte della deserializzazione -> errore.

Come faccio a superarlo con modifiche minime al mio codice?

Cordiali saluti, Yossi.

+0

nota minore: "protobuf-net" è solo un'implementazione; ci sono altre implementazioni di C# protobuf. Lo dico solo per spiegare perché ho cambiato il titolo –

risposta

5

L'opzione più semplice è probabilmente qui:

[ProtoContract(SkipConstructor = true)] 

che, come si dice, non esegue il costruttore (o campo-inizializzatori). Si noti che questo lascerà il dizionario nullo se non ci sono dati. Un altro approccio potrebbe essere quello di utilizzare un callback di serializzazione (che spara appena prima che venga caricato con i dati):

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

Una terza opzione consiste nel combinare quanto sopra utilizzando:

[ProtoContract(SkipConstructor = true)] 

e:

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

per impostarlo su un dizionario vuoto anche se non c'erano dati. Nota si avrebbe bisogno di fare questo da Father troppo, dal momento che utilizza il Son costruttore di default.

+0

Grazie mille, Marc. Ho provato i tuoi suggerimenti e hanno risolto il mio problema. Credo che andrò con la terza opzione (meno impegnativa). Yossi. – yossic

Problemi correlati