Частичная десериализация из BinaryFormatter
От: A.Zanevski  
Дата: 10.09.09 14:08
Оценка:
Привет всем,
В старой версии программы список объектов со сложной внутренней структурой (внутри объектов есть списки других объектов со своей структурой) сохранялся через BinaryFormatter. В новой версии классы были пересмотрены — поменялись и названия классов и их внутреннее содержимое. Но для удобства пользователя надо прочитать некоторые поля из старого файла. Как это сделать не таская старые классы?
Я задаю в BinaryFormatter.Binder класс который для старых классов верхнего уровня (которые непосредственно хранятся в списке) выдает тип нового класса с реализацией ISerializable. Но при вызове BinaryFormatter.Deserialize в конструктор десериализации не вызывается, хотя Binder отрабатывает. Скорее всего десериализация начинается с самых вложенных объектов и там возникает ошибка. Как пропустить десериализацию вложенных объектов?
Re: Частичная десериализация из BinaryFormatter
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.09.09 16:25
Оценка: +1 :)
Здравствуйте, A.Zanevski, Вы писали:

Никак. Не надо использовать BinaryFormatter для таких целей.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237 on Windows 7 6.1.7100.0>>
AVK Blog
Re: Частичная десериализация из BinaryFormatter
От: Nonmanual Worker  
Дата: 11.09.09 03:48
Оценка:
Здравствуйте, A.Zanevski, Вы писали:

AZ>В старой версии программы список объектов со сложной внутренней структурой (внутри объектов есть списки других объектов со своей структурой) сохранялся через BinaryFormatter. В новой версии классы были пересмотрены — поменялись и названия классов и их внутреннее содержимое. Но для удобства пользователя надо прочитать некоторые поля из старого файла. Как это сделать не таская старые классы?

AZ>Я задаю в BinaryFormatter.Binder класс который для старых классов верхнего уровня (которые непосредственно хранятся в списке) выдает тип нового класса с реализацией ISerializable. Но при вызове BinaryFormatter.Deserialize в конструктор десериализации не вызывается, хотя Binder отрабатывает. Скорее всего десериализация начинается с самых вложенных объектов и там возникает ошибка. Как пропустить десериализацию вложенных объектов?

Такие проблемы продумываются заранее. Я в свое время сделал сериализатор с поддержкой версионности классов. В случае несоответствия версий засериализованного класса и класса-назначения десерализация выполняется заранее предусмотренным кодом.
Для вас я выхода другого не вижу — только тащить старые классы.
Re[2]: Частичная десериализация из BinaryFormatter
От: A.Zanevski  
Дата: 11.09.09 07:23
Оценка:
Здравствуйте, Nonmanual Worker, Вы писали:

NW>Такие проблемы продумываются заранее. Я в свое время сделал сериализатор с поддержкой версионности классов. В случае несоответствия версий засериализованного класса и класса-назначения десерализация выполняется заранее предусмотренным кодом.

Код писался в предыдущей версии? Что он делал (в общих чертах, если не секрет)?
Re[3]: Частичная десериализация из BinaryFormatter
От: Nonmanual Worker  
Дата: 11.09.09 15:08
Оценка:
Здравствуйте, A.Zanevski, Вы писали:

AZ>Код писался в предыдущей версии? Что он делал (в общих чертах, если не секрет)?

Возможность закладывалась при разработке.
А идея была такая:
1) Есть класс атрибута для "пометки" классов, в котором прописывался алиас "помечаемого" класса (т.е. короткое символическое имя класса) и целое число — версия класса.
    [AttributeUsage(AttributeTargets.Class)]
    public class CustomSerializableAttribute : Attribute
    {
        ...
        public CustomSerializableAttribute(string classAlias, int classVersion)
        ...
    }


2) Есть интерфейс, которые должны реализовывать классы для возможности сериализации\десерализации, типа
    public interface ICustomSerializable
    {
        void WriteObject(CustomSerializationWriter writer);
        void ReadObject(CustomSerializationReader reader, int classVersion);
    }


3) Смысл такой, при сериализации объекта он сам сериализует свои свойства (или там поля) типа значения, каждый аггрегируемый в нем "сложный" объект сериализует себя сам. Сама запись данных в файл\поток\реестр\"или куда там нужно" выполняется с помощью объекта типа производного от CustomSerializationWriter. Помимо значений свойств\полей туда пишется еще и нифа а алиасе класса и версии.
При десереализации сперва читается алиас класс, создается объект соотв. типа, который десерализует себя сам, получив в качестве входного параметра версию сохраненного серализованного класса, программист предусматрительно пишет код, который десерализует старые сериализованные версии.
Внешне все выглядит похоже на встроенную сериализацию, разница лишь в том, что в классах прописаны варианты десериализации в зависимости от версии, что пришла на вход. Что-то типа (простой пример)
        public void WriteObject(CustomSerializationWriter writer)
        {
            writer.WriteString("name", _name);
            writer.WriteObject(_items, "items");
        }

        public void ReadObject(CustomSerializationReader reader, int classVersion)
        {
            if (classVersion == 1)
                reader.ReadString("name", ref _name);
            else
                reader.ReadString("alias", ref _name);
            reader.ReadObject(_items, "items");
        }

и задача пользователя этого механизма только в написании вот подобных вещей.
Создание объектов, заполнение коллекций все делается автоматически через рефлексию.
Простите что несколько написано сумбурно, в C# я новичек.
Re[4]: Частичная десериализация из BinaryFormatter
От: A.Zanevski  
Дата: 11.09.09 15:48
Оценка:
Ясно. Спасибо!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.