Можно ли использовать OnDeserializedAttribute вместо интерфейса IDeserializationCallback? - PullRequest
7 голосов
/ 26 октября 2010

Поскольку MSDN заявляет здесь , это может.Но я потратил 2 часа на копирование кода mscorlib, потому что в некоторых случаях BinaryFormatter вызывал мой метод, помеченный OnDeserialized до конструктора десериализации.То есть ордер был

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

Пока я ожидал, что он будет

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

И последний пункт.Когда я реализовал интерфейс IDeserializationCallback, его метод OnDeserialization назывался AFTER constructor, как я и ожидал.

Я пытался воспроизвести это на некоторой простой структуре классов, но там все работало нормально.В нашем проекте граф объектов сериализуется очень сложно, поэтому я не знаю, куда копать.Проверка кода mscorlib с помощью рефлектора не сильно помогла - код десериализации слишком сложен, чтобы я мог понять, откуда возникла проблема.

Итак, кто-нибудь знает, что может быть причиной такой проблемы?Мы используем предположение, что OnDeserialized называется ДО конструктора в нескольких других местах, поэтому я боюсь теперь, что он не очень надежен ...

Спасибо!

1 Ответ

6 голосов
/ 16 января 2012

Наконец, у меня есть ответ на свой вопрос, если кому-то будет интересно. Рассмотрим пример в конце этого поста. Есть два класса, экземпляры которых содержат ссылки друг на друга. При таких условиях невозможно, чтобы десериализованные конструкторы обоих экземпляров были переданы с построенными объектами. Таким образом, сериализатор сначала вызывает один из конструкторов, передавая ему неструктурированный экземпляр второго типа, а затем вызывает конструктор этого объекта, передавая ему созданный экземпляр первого типа. Таким образом, это помогает нам восстановить соединения объектов, так что это действительно лучшее, что он может сделать!

Далее, OnDeserializing и OnDeserialized обратные вызовы в таких случаях могут быть вызваны, как я указал в вопросе, в то время как OnDeserialization метод IDeserializationCallback всегда вызывается после десериализации графа ПОЛНЫХ объектов, точно так же, как он указано в его спецификации.

Имея в виду все вышесказанное, я считаю, что лучше всего использовать интерфейс IDeserializationCallback для любой необходимой обработки после десериализации. В этом случае я уверен, что конструкторы вызываются для всех объектов, и я могу делать необходимые изменения «безопасным» способом.

      [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);
      }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...