Can OnDeserializedAttribute be used instead of IDeserializationCallback interface?

不打扰是莪最后的温柔 提交于 2019-12-22 05:07:29

问题


As MSDN states here, it can. But I've spent 2 hours digging mscorlib code, because in some cases the BinaryFormatter called my method marked with OnDeserialized BEFORE deserialization constructor. That is, the order was

OnDeserializing(StreamingContext context)
OnDeserialized(StreamingContext context)
.ctor(SerializationInfo info, StreamingContext context)

While I was expecting it to be

OnDeserializing(StreamingContext context)
.ctor(SerializationInfo info, StreamingContext context)
OnDeserialized(StreamingContext context)

And the final point. When I implemented IDeserializationCallback interface, its method OnDeserialization was called AFTER constructor, as I wanted and expected.

I tried to reproduce this on some simple class structure, but there everything worked fine. In our project the objects graph being serialized is very complex, so I do not know where to dig. Inspecting the mscorlib code with reflector did not help a lot - the deserialization code is too complicated for me to figure out where the problem comes from.

So, does anybody know what could be causing such problem? We use the assumption that OnDeserialized is called BEFORE the constructor in several other places so I am scared now that it is not very reliable...

Thanks!


回答1:


Finally, I have the answer to my own question, if anyone would be interested. Consider the example in the end of this post. There are two classes, instances of which contain references to each other. Under such conditions there is no possibility that deserializing constructors of both instances are passed with constructed objects. So serializer first calls one of constructors passing it an unconstructed instance of second type and then calls constructor of that object, passing it constructed instance of first type. In such a way it helps us to restore objects connections, so it is really the best it can do!

Next, OnDeserializing and OnDeserialized callbacks in such cases may be called as I pointed in the question, while OnDeserialization method of IDeserializationCallback is always called after the COMPLETE objects graph has been deserialized, exactly as it is stated in its specification.

Keeping all the above in mind, I find it the best to use IDeserializationCallback interface to do any post-deserialization processing I need. In that case I am sure that constructors are called for all objects and I can do necessary modifications in a 'safe' way.

      [Serializable]
      class One :ISerializable, IDeserializationCallback
      {
           public Two m_two;
           public One() {}
           public One(SerializationInfo info, StreamingContext context)
           {
                var two = (Two)info.GetValue("m_two", typeof(Two));
                m_two = two;
           }
           public void GetObjectData(SerializationInfo info, StreamingContext context)
           {
                info.AddValue("m_two", m_two);
           }
           private bool m_onDeserializing;
           private bool m_onDeserialized;
           private bool m_callback;
           public void OnDeserialization(object sender)
           {
                m_callback = true;
           }
           [OnDeserializing]
           void OnDeserializing(StreamingContext context)
           {
                m_onDeserializing = true;
           }

           [OnDeserialized]
           void OnDeserialized(StreamingContext context)
           {
                m_onDeserialized = true;
           }
      }

      [Serializable]
      private class Two : ISerializable, IDeserializationCallback
      {
           public Two(){}
           public One m_one;
           public Two(SerializationInfo info, StreamingContext context)
           {
                var one = (One)info.GetValue("m_one", typeof(One));
                m_one = one;
           }
           public void GetObjectData(SerializationInfo info, StreamingContext context)
           {
                info.AddValue("m_one", m_one);
           }
           private bool m_onDeserializing;
           private bool m_onDeserialized;
           private bool m_callback;
           public void OnDeserialization(object sender)
           {
                m_callback = true;
           }
           [OnDeserializing]
           void OnDeserializing(StreamingContext context)
           {
                m_onDeserializing = true;
           }
           [OnDeserialized]
           void OnDeserialized(StreamingContext context)
           {
                m_onDeserialized = true;
           }
      }

      [STAThread]
      static void Main()
      {
           var one = new One();
           one.m_two = new Two();
           one.m_two.m_one = one;

           BinaryFormatter formatter = new BinaryFormatter();
           MemoryStream mss =new MemoryStream();
           formatter.Serialize(mss, one);
           mss.Position = 0;
           var deserialize = formatter.Deserialize(mss);
      }


来源:https://stackoverflow.com/questions/4023644/can-ondeserializedattribute-be-used-instead-of-ideserializationcallback-interfac

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!