2010-10-26 10 views
6

Como dice MSDN here, puede hacerlo. Pero he pasado 2 horas cavando código mscorlib, porque en algunos casos el BinaryFormatter llamó a mi método marcado con OnDeserialized ANTES del constructor de deserialización. Es decir, el orden era¿Se puede usar OnDeserializedAttribute en lugar de la interfaz IDeserializationCallback?

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

Mientras yo esperaba que fuera

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

Y el punto final. Cuando implementé la interfaz IDeserializationCallback, su método OnDeserialization se llamó DESPUÉS del constructor, como quería y esperaba.

Intenté reproducir esto en una estructura de clase simple, pero allí todo funcionó bien. En nuestro proyecto, el gráfico de objetos que se serializa es muy complejo, por lo que no sé dónde cavar. Inspeccionar el código de mscorlib con reflector no ayudó mucho; el código de deserialización es demasiado complicado para descubrir de dónde viene el problema.

Entonces, ¿alguien sabe lo que podría estar causando ese problema? Usamos la suposición de que OnDeserialized se llama ANTES del constructor en varios otros lugares, así que ahora tengo miedo de que no sea muy confiable ...

¡Gracias!

Respuesta

5

Finalmente, tengo la respuesta a mi propia pregunta, si alguien estaría interesado. Considera el ejemplo al final de esta publicación. Hay dos clases, instancias de las cuales contienen referencias entre sí. Bajo tales condiciones no hay posibilidad de que los constructores deserializadores de ambas instancias pasen con objetos construidos. Entonces, el serializador llama primero a uno de los constructores que le pasan una instancia no reconstruida de segundo tipo y luego llama al constructor de ese objeto, pasándole una instancia construida de primer tipo. De esta forma, nos ayuda a restablecer las conexiones de los objetos, ¡así que realmente es lo mejor que puede hacer!

A continuación, OnDeserializing y OnDeserialized devoluciones de llamada en tales casos pueden ser llamados como he señalado en la pregunta, mientras que OnDeserialization método de IDeserializationCallback siempre se llama después de que el gráfico de objetos completos ha sido deserializado, tal y como se afirma en su especificación.

Teniendo todo lo anterior en mente, creo que es mejor utilizar la interfaz IDeserializationCallback para hacer cualquier proceso de deserialización posterior que necesite. En ese caso, estoy seguro de que los constructores son llamados para todos los objetos y puedo hacer las modificaciones necesarias de una manera "segura".

 [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); 
     } 
Cuestiones relacionadas