Конструктор десериализации не называется

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

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

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

[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() вызывается как на моем шаблоне, так и на моем разделе, что заставляет меня думать, что данные являются Serializable и что он становится сериализованным.

Когда я десериализуюсь, вызывается только конструктор десериализации на Шаблон. Конструктор десериализации для раздела никогда не вызывается. Результатом этого является то, что вызов info.GetValue("Section_Values"....) возвращает список, но в нем есть один элемент и этот элемент имеет значение null.

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

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

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

Update..

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

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 - пустой метод. Я не пытаюсь ничего сделать с десериализованными данными.
  • Базовый конструктор для раздела был заглушен, чтобы передать новые действительные объекты, и я подтвердил, что это нормально.
  • Не исключены исключения, чтобы сказать, что CustomObject не может быть сериализован.
  • CustomObject является сериализуемым, и его метод GetObjectData() работает отлично, и его сконструировано отлично при десериализации.

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

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

Ответ 1

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

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

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

Ответ 2

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

Эти разделы, тем не менее, еще не были де-сериализованы, они будут десериализованы после того, как шаблон завершит де-сериализацию. Вы должны быть в состоянии проверить это, используя точку останова и позволяя вашему коду работать немного дальше. Способ исправить это либо решение 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]);
        } 
    }
}