I assume you are using BinaryFormatter .
BinaryFormatter - graph serializer. Instead of objects being stored in a clean tree, they are assigned temporary object identifiers and stored in the form in which they occur. Thus, when an object is deserialized, it is not guaranteed that all referenced objects were previously deserialized. Thus, the entries in your forwardMap are not populated yet.
The usual workaround is to add an IDeserializationCallback to your class and build your inverseMap and inverseInstance after everything has been deserialized in the OnDeserialization method. But Dictionary<TKey, TValue> also implements IDeserializationCallback , which introduces an additional sequencing problem: it was not guaranteed to be called before yours. In this thread, Microsoft writes :
Objects are reconstructed internally, and invocation methods during deserialization may have undesirable side effects, since invoked methods may refer to references to objects that were not deserialized by the time the call ended. If the deserialized class implements IDeserializationCallback, the OnSerialization method will be automatically called when the entire object graph is deserialized. At this point, all the referenced child objects have been fully restored. A hash table is a typical example of a class that is difficult to deserialize without using the event listener described above. It is easy to get key / value pairs during deserialization, but adding these objects back to the hash table can cause problems because there is no guarantee that classes derived from the hash table are deserialized. Therefore, calling methods in a hash table at this stage are impractical.
So you can do a couple of things:
Instead of saving Dictionary<TKey,TValue> , save the array KeyValuePair<TKey,TValue> . This has the advantage that your binary data is simpler, but you need to allocate an array in your GetObjectData() method.
Or follow the recommendations in the 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.
those. in your callback, call the OnDeserialization method of your nested dictionary before using it:
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); }
(If you prefer, you can do this in [OnDeserialied] .)
By the way, this blog post claims that it is safe to call the OnDeserialization HashTable method from the deserialization constructor containing the class, and not later OnDeserialization , so you can try it.
source share