Конструктор десериализации не вызывается - PullRequest
11 голосов
/ 01 декабря 2011

Я пытаюсь сериализовать / десериализовать объект, который содержит Dictionary<Tuid,Section>. Это оба пользовательских типа.

В моем коде у меня есть тип Шаблон , который содержит Dictionary<Tuid,Section>. Это класс Template , который я пытаюсь сериализовать / десериализовать.

Чтобы решить проблему, связанную с тем, что эта коллекция является словарем, я реализовал интерфейс ISerializable в своем классе Template ....

[Serializable]
public class Template : ISerializable
{
    protected Template(SerializationInfo info, StreamingContext context)
    {
        // Deserialize the sections
        List<Tuid> tuids = (List<Tuid>)info.GetValue("Sections_Keys", typeof(List<Tuid>));
        List<Section> sections = (List<Section>)info.GetValue("Sections_Values", typeof(List<Section>));
        this._sections = new Dictionary<Tuid, Section>();

        for (int i = 0; i < tuids.Count; i++)
        {
            _sections.Add(tuids[i], sections[i]);
        }           
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        List<Tuid> tuids = new List<Tuid>();
        List<Section> sections = new List<Section>();

        foreach (KeyValuePair<Tuid, Section> kvp in _sections)
        {
            tuids.Add(kvp.Key);
            sections.Add(kvp.Value);
        }

        info.AddValue("Sections_Keys", tuids, typeof(List<Tuid>));
        info.AddValue("Sections_Values", sections, typeof(List<Section>));
   }

Стратегия здесь заключается в том, чтобы «распаковать» словарь в два отдельных списка и сохранить их отдельно в сериализованном потоке. Затем они воссоздаются потом.

Мой Раздел Класс также влияет ISerializable ...

[Serializable]
public class Section : BaseObject
{

    protected Section(SerializationInfo info, StreamingContext context):base(.....)
    {
        // Code
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
       // code
    }
}

Проблема в том, что при сериализации GetObjectData() вызывается как в моем шаблоне , так и в моем разделе, что заставляет меня поверить, что данные являются сериализуемыми и их сериализация.

Когда я десериализую, only вызывается конструктор десериализации в Template. Конструктор десериализации для Section никогда не вызывается. В результате этого вызов info.GetValue("Section_Values"....) возвращает список, но в нем есть один элемент, и этот элемент является нулевым.

Почему мой конструктор для десериализации секции никогда не вызывается? Может ли быть так, что некоторые данные внутри раздела не сериализуемы? Если так, как узнать, что именно он не может сериализовать?

Обновление: я только что заметил, что BaseObject для раздела помечен [Serializable], но не реализует ISerializable.

Кроме того, мне интересно, насколько суетлив код десериализации - будет ли он предназначен для конструктора, который также создает базовый класс?

Обновление ..

Хорошо, я отследил проблему до Сериализации Секции. Код выглядит примерно так ...

protected Section(SerializationInfo info, StreamingContext context):base(.....)
{
    // Code
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{

    //info.AddValue("CustomObject", ClientInfo, typeof(CustomObject));
    //info.AddValue("Description", Description, typeof(string));
}

С обеими закомментированными строками ничего не сериализуется, и конструктор десериализации вызывается на Section. Если я добавлю в строковое значение все еще хорошо. Однако, да, как вы уже догадались, если я добавлю CustomObject в поток сериализации, конструктор десериализации не будет вызван.

Обратите внимание, что ...

  • Мой конструктор десериализации для Section - пустой метод - я не пытаюсь что-либо делать с десериализованными данными.
  • Базовый конструктор для Section был заглушен для передачи новых допустимых объектов, и я подтвердил, что это работает нормально.
  • Нет исключений, сообщающих мне, что CustomObject нельзя сериализовать.
  • CustomObject является сериализуемым, и его метод GetObjectData() работает нормально, а его построенный штраф - при десериализации.

Кажется странным, что если просто добавить этот сериализуемый объект в поток, то после этого фреймворк просто перестанет работать с конструктором десериализатора Section !!

Почему это могло произойти?

Ответы [ 2 ]

11 голосов
/ 01 декабря 2011

Один из вариантов - реализовать

[OnDeserializing]
void OnDeserializing(StreamingContext c)
{
    //create what is required here
}

в классе Template, поскольку сериализатор по умолчанию не вызывает конструктор для дочерних объектов - Section class

2 голосов
/ 01 декабря 2011

Я полагаю, что ваша проблема в том, как работает сериализация (кажется, я вспоминаю сначала ее ширину, а не глубину). Это означает, что он десериализует ваш шаблон, а затем создает внутри него пространство для добавления в ваши разделы.

Однако эти разделы еще не десериализованы, они будут десериализованы после завершения десериализации шаблона. Вы должны быть в состоянии проверить это, используя точку останова и позволяя вашему коду работать дальше. Способ исправить это - либо решение oleksii, либо аналогичное использование IDeserializationCallback.

Что такое IDeserializationCallback, когда экземпляр завершает десериализацию (и его членов), он вызывает метод, позволяющий вам выполнить некоторую разводку. Я бы попробовал что-то похожее на это ниже:

[Serializable]
public class Template : ISerializable, IDeserializationCallback
{
    private List<Tuid> tuids;
    private List<Section> sections
    protected Template(SerializationInfo info, StreamingContext context)
    {
        tuids = (List<Tuid>)info.GetValue("Sections_Keys", typeof(List<Tuid>));
        sections = (List<Section>)info.GetValue("Sections_Values", typeof(List<Section>));
        this._sections = new Dictionary<Tuid, Section>();
    }

    public void OnDeserialization(object sender)
    {
        // Section serialization constructor should have been called by this point
        for (int i = 0; i < tuids.Count; i++)
        {
            _sections.Add(tuids[i], sections[i]);
        } 
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...