2011-11-01 9 views
5

मैं सी # मार्क Gravell द्वारा लिए Protobuf साथ एक मौजूदा serializer को बदलने के लिए कोशिश कर रहा हूँ के साथ "एक ही कुंजी के साथ एक आइटम पहले से ही जोड़ दिया गया है"। मेरा कोड व्यापक है और मेरा लक्ष्य न्यूनतम परिवर्तनों के साथ स्विच करने में सक्षम होना है। विशेष रूप से एक समाधान है कि मेरी पहले से ही विद्यमान कोड और कक्षाओं में कम से कम परिवर्तन की आवश्यकता होगी -त्रुटि 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 पैदा करता है। मुझे लगता है कि जब प्रोटोबफ ऑब्जेक्ट को पुनर्निर्माण करने की कोशिश करता है तो इसे एक ही कन्स्ट्रक्टर का उपयोग करता है (इस प्रकार मूल्यों के साथ शब्दकोश को भी शुरू करता है) और फिर deserializing -> त्रुटि के हिस्से के रूप में एक ही मान को फिर से धक्का देने का प्रयास करता है।

कैसे मैं इसे अपने कोड के लिए कम से कम परिवर्तन के साथ दूर कर सकते हैं?

सधन्यवाद, योसी।

+0

मामूली नोट: "प्रोटोबफ-नेट" केवल एक कार्यान्वयन है; अन्य सी # प्रोटोबफ कार्यान्वयन भी हैं। मैं केवल यह बताने के लिए इसका जिक्र करता हूं कि मैंने शीर्षक –

उत्तर

5

यहाँ सबसे आसान विकल्प शायद है:

[ProtoContract(SkipConstructor = true)] 

जो, के रूप में यह कहते हैं, निर्माता (या क्षेत्र initializers) पर अमल नहीं होंगे। ध्यान दें कि यदि कोई डेटा नहीं है तो यह शब्दकोश शून्य को छोड़ देगा।

[ProtoContract(SkipConstructor = true)] 

और:

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

एक तीसरा विकल्प का उपयोग करके ऊपर गठबंधन करने के लिए होगा: एक और दृष्टिकोण एक क्रमबद्धता कॉलबैक (जो आग बस से पहले ही डेटा के साथ भरी हुई हो जाता है) का उपयोग हो सकता है

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

डिफ़ॉल्ट डेटा को डिफॉल्ट करने के लिए डिफ़ॉल्ट रूप से डिफॉल्ट करने के लिए, यदि कोई डेटा नहीं था। ध्यान दें कि आपको इसे Father से भी करना होगा, क्योंकि यह डिफ़ॉल्ट Son कन्स्ट्रक्टर का उपयोग करता है।

+0

शीर्षक क्यों बदल दिया, धन्यवाद। मैंने आपके सुझावों की कोशिश की और वे मेरी समस्या का समाधान करते हैं। मेरा मानना ​​है कि मैं तीसरे विकल्प (कम से कम संसाधन मांग) के साथ जाऊंगा। योसी। – yossic