2014-08-30 10 views
5

पर खाली है, मैं वर्तमान में एक बिडरेक्शनल मैप क्लास लिख रहा हूं, और मुझे कक्षा के क्रमिकरण/deserialization (नीचे सवाल) के साथ कुछ परेशानी हो रही है।शब्दकोश deserialization

यहां कक्षा के कुछ हिस्सों प्रासंगिक हैं।

/// <summary> 
/// Represents a dictionary where both keys and values are unique, and the mapping between them is bidirectional. 
/// </summary> 
/// <typeparam name="TKey"> The type of the keys in the dictionary. </typeparam> 
/// <typeparam name="TValue"> The type of the values in the dictionary. </typeparam> 
[Serializable] 
public class BidirectionalDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IEquatable<BidirectionalDictionary<TKey, TValue>>, ISerializable, IDeserializationCallback 
{ 

     /// <summary> 
     /// A dictionary that maps the keys to values. 
     /// </summary> 
     private readonly Dictionary<TKey, TValue> forwardMap; 

     /// <summary> 
     /// A dictionary that maps the values to keys. 
     /// </summary> 
     private readonly Dictionary<TValue, TKey> inverseMap; 

     /// <summary> 
     /// An instance of the dictionary where the values are the keys, and the keys are the values. 
     /// </summary> 
     private readonly BidirectionalDictionary<TValue, TKey> inverseInstance; 

     /// <summary> 
     /// Initializes a new instance of the dictionary class with serialized data. </summary> 
     /// </summary> 
     /// <param name="info"> The serialization info. </param> 
     /// <param name="context"> The sserialization context. </param> 
     protected BidirectionalDictionary(SerializationInfo info, StreamingContext context) 
     { 
      this.forwardMap = (Dictionary<TKey, TValue>)info.GetValue("UnderlyingDictionary", typeof(Dictionary<TKey, TValue>)); 
      this.inverseMap = new Dictionary<TValue, TKey>(
       forwardMap.Count, 
       (IEqualityComparer<TValue>)info.GetValue("InverseComparer", typeof(IEqualityComparer<TValue>))); 

      // forwardMap is always empty at this point. 
      foreach (KeyValuePair<TKey, TValue> entry in forwardMap) 
       inverseMap.Add(entry.Value, entry.Key); 

      this.inverseInstance = new BidirectionalDictionary<TValue, TKey>(this); 
     } 

     /// <summary> 
     /// Gets the data needed to serialize the dictionary. 
     /// </summary> 
     /// <param name="info"> The serialization info. </param> 
     /// <param name="context"> The serialization context. </param> 
     public void GetObjectData(SerializationInfo info, StreamingContext context) 
     { 
      info.AddValue("UnderlyingDictionary", forwardMap); 
      info.AddValue("InverseComparer", inverseMap.Comparer); 
     } 
} 

आगे और inverseMap शब्दकोशों के बाद ठीक उसी डेटा होते हैं, मेरा विचार उनमें से केवल एक (forwardMap) क्रमानुसार करने, और फिर अक्रमांकन पर यह डेटा से अन्य (inverseMap) का निर्माण किया गया था। हालांकि, inverseMap deserialization कन्स्ट्रक्टर में किसी भी डेटा के साथ आबादी नहीं मिल रहा है। ऐसा लगता है कि फॉरवर्ड मैप डिक्शनरी केवल वर्ग के deserialization कन्स्ट्रक्टर पहले ही निष्पादित होने के बाद पूरी तरह से deserialized है।

इसे ठीक करने के तरीके पर कोई विचार?

+0

बस पुष्टि करने के लिए, क्या आप ['बाइनरीफॉर्मेटर'] (http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter%28v=vs.110% का उपयोग कर रहे हैं 29.aspx)? – dbc

+0

क्या आप पूरा कोड पोस्ट कर सकते हैं ताकि हम इसे सीधे जांच सकें? –

+0

पूर्ण कोड को संपादित और पोस्ट करने वाला था, लेकिन समस्या ठीक है जो @ डीबीसी नीचे बताई गई है। तो हाँ, मैं बाइनरीफॉर्मेटर का उपयोग कर रहा हूँ। – Henrik

उत्तर

7

मुझे लगता है कि आप BinaryFormatter का उपयोग कर रहे हैं।

BinaryFormatter एक ग्राफ धारावाहिक है। एक शुद्ध पेड़ में वस्तुओं को संग्रहीत करने के बजाय, उन्हें अस्थायी ऑब्जेक्ट आईडी आवंटित किए जाते हैं और उनका सामना किया जाता है। इस प्रकार जब एक वस्तु deserialized है, यह गारंटी नहीं है कि सभी संदर्भित वस्तुओं को पहले deserialized किया गया है। इस प्रकार यह संभव है कि आपके forwardMap में प्रविष्टियां अभी तक भर चुकी नहीं हैं।

सामान्य तरीके को अपनी कक्षा में IDeserializationCallback तर्क जोड़ने के लिए, हो जाएं और अपने inverseMap और inverseInstance के बाद सब कुछ OnDeserialization विधि में deserialized कर दिया गया है के लिए है। लेकिन, Dictionary<TKey, TValue> भी IDeserializationCallback लागू करता है, जो एक अतिरिक्त अनुक्रमिक समस्या का परिचय देता है: यह आपके पहले कहने की गारंटी नहीं है। इस विषय पर, Microsoft writes:

वस्तुओं के अंदर बाहर से निकाले जाते हैं, और अक्रमांकन दौरान तरीकों बुला, अवांछनीय दुष्प्रभाव हो सकते हैं के बाद से पद्धतियों को बुलाया संदर्भ उस समय कॉल द्वारा deserialized नहीं किया गया है आपत्ति भी दिखाई दे सकता से बना। यदि वर्ग deserialized IDEerialializationCallback लागू करता है, तो पूरे ऑब्जेक्ट ग्राफ को deserialized किया गया है जब OnSerialization विधि स्वचालित रूप से बुलाया जाएगा। इस बिंदु पर, संदर्भित सभी बाल वस्तुओं को पूरी तरह से बहाल कर दिया गया है। एक हैश टेबल एक वर्ग का एक विशिष्ट उदाहरण है जो ऊपर वर्णित घटना श्रोता का उपयोग किए बिना deserialize करना मुश्किल है। Deserialization के दौरान कुंजी/मूल्य जोड़े को पुनर्प्राप्त करना आसान है, लेकिन इन ऑब्जेक्ट्स को हैश टेबल पर वापस जोड़ना समस्याएं पैदा कर सकता है क्योंकि इस बात की कोई गारंटी नहीं है कि हैश तालिका से प्राप्त कक्षाओं को deserialized किया गया है। इस चरण में हैश टेबल पर कॉलिंग विधियां इसलिए सलाह नहीं दी जाती हैं।

  1. बल्कि एक Dictionary<TKey,TValue> भंडारण की तुलना में, KeyValuePair<TKey,TValue> की एक सरणी की दुकान:

इस प्रकार नीचे दिए कुछ तुम कर सकते हो रहे हैं। इसका आपके बाइनरी डेटा को सरल बनाने का लाभ है, लेकिन आपको अपने GetObjectData() विधि में सरणी आवंटित करने की आवश्यकता है।

  • या dictionary reference source में सलाह का पालन करें:

    // It might be necessary to call OnDeserialization from a container if the container object also implements 
    // OnDeserialization. However, remoting will call OnDeserialization again. 
    // We can return immediately if this function is called twice. 
    // Note we set remove the serialization info from the table at the end of this method. 
    

    अर्थातअपने कॉलबैक में, उपयोग करने से पहले अपने नेस्टेड शब्दकोश की OnDeserialization विधि कॉल:

    public partial class BidirectionalDictionary<TKey, TValue> : IDeserializationCallback 
    { 
        public void OnDeserialization(object sender) 
        { 
         this.forwardMap.OnDeserialization(sender); 
         foreach (KeyValuePair<TKey, TValue> entry in forwardMap) 
         { 
          this.inverseMap.Add(entry.Value, entry.Key); 
         } 
         // inverseInstance will no longer be able to be read-only sicne it is being allocated in a post-deserialization callback. 
         this.inverseInstance = new BidirectionalDictionary<TValue, TKey>(this); 
        } 
    

    (। आप इसे एक [OnDeserialied] विधि के बजाय यदि आप पसंद में कर सकता है)

  • संयोग से, this blog post दावा है कि यह OnDeserialization से बाद में एक युक्त वर्ग के अक्रमांकन निर्माता से एक HashTable की OnDeserialization विधि कॉल करने के बजाय सुरक्षित है, तो आप कि एक कोशिश दे सकता है।

    +0

    यह समस्या का बिल्कुल कारण था। मैंने वास्तव में IDeserializationCallback दृष्टिकोण का प्रयास किया था, लेकिन जाहिर है कि यह काम नहीं करता है (चूंकि शब्दकोश के पास भी इसका स्वयं का कॉलबैक है)। नाउ इट आल मेक्स सेंस। – Henrik

    संबंधित मुद्दे