[Serializable]
public class Personage: ISerializable
{…}
Добавим в наш класс специальный метод, вызываемый при сериализации — метод сохранения данных:
//Специальный метод сериализации
public void GetObjectData(Serializationlnfо info,
StreamingContext context)
{
info.AddValue("name",name); infо. AddValue("age", age);
infо.AddValue("status",status);
infо.AddValue("wealth", wealth);
info.AddValue("couplename",couple.name);
info.AddValue("coupleage", couple.age);
infо.AddValue("couplestatus",couple.status);
infо. AddValue("couplewealth", couple.wealth);
}
В трех первых строках сохраняются значимые поля объекта и тут все ясно. Но вот запомнить поле, хранящее объект couple класса Personage, напрямую не удается. Попытка рекурсивного вызова
couple.GetobjectData(info,context);
привела бы к зацикливанию, если бы раньше из-за повторяющегося ключа не возникала исключительная ситуация в момент записи поля name объекта couple. Поэтому приходится явно сохранять поля этого объекта уже с другими ключами. Понятно, что с ростом сложности структуры графа объектов задача существенно осложняется.
Добавим в наш класс специальный конструктор, вызываемый при десериализации — конструктор восстановления состояния:
//Специальный конструктор сериализации
protected Personage (Serializationlnfo info,
StreamingContext context)
{
name = infо. GetString("name"); age = infо. Getlnt32("age");
status = infо. GetString("status");
wealth = infо. GetString("wealth");
couple = new Personage(infо. GetString("couplename"),
infо. Getlnt32("coupleage"));
couple.status = infо. GetString("couplestatus");
couple.wealth = infо. GetString("couplewealth");
this.couple = couple; couple.couple = this;
}
Опять первые строки восстановления значимых полей объекта прозрачно ясны. А с полем couple приходится повозиться. Вначале создается новый объект обычным конструктором, аргументы которого читаются из сохраняемой памяти. Затем восстанавливаются значения других полей этого объекта, а затем уже происходит взаимное связывание двух объектов.
Кроме введения конструктора класса и метода GetObjectData, никаких других изменений в проекте не понадобилось — ни в методах класса, ни на стороне клиента. Внешне проект работал совершенно идентично ситуации, когда не вводилось наследование интерфейса сериализации. Но с внутренних позиций изменения произошли: методы форматеров Serialize и Deserialize в процессе своей работы теперь вызывали созданный нами метод и конструктор класса. Небольшие изменения произошли и в файлах, хранящих данные.
Мораль: должны быть веские основания для отказа от стандартно реализованной сериализации. Повторюсь, такими основаниями могут служить необходимость в уменьшении объема файла, хранящего данные, и в сокращении времени передачи данных.
Когда в нашем примере вводилось собственное управление сериализацией, то не ставилась цель минимизации объема хранимых данных, в обоих случаях сохранялись одни и те же данные. Тем не менее представляет интерес взглянуть на таблицу, хранящую объемы создаваемых файлов.
Таблица 19.1. Размеры файлов при различных случаях сериализации
Формат ∙ Сериализация ∙ Размер файла
Бинарный поток ∙ Стандартная ∙ 355 байтов
Бинарный поток ∙ Управляемая ∙ 355 байтов
XML-документ ∙ Стандартная ∙ 1,14 Кб.
XML-документ ∙ Управляемая ∙ 974 байта
Преимуществами XML-документа являются его читабельность и хорошо развитые средства разбора, но зато бинарное представление выигрывает в объеме и скорости передачи тех же данных.
20. Функциональный тип в С#. Делегаты
Новое слово для старого понятия. Функциональный тип. Функции высших порядков. Вычисление интеграла и сортировка. Два способа взаимодействия частей при построении сложных систем. Функции обратного вызова. Наследование и функциональные типы. Сравнение двух подходов. Класс Delegate. Методы и свойства класса. Операции над делегатами. Комбинирование делегатов. Список вызовов.
Слово делегат (delegate) используется в C# для обозначения хорошо известного понятия. Делегат задает определение функционального типа (класса) данных. Экземплярами класса являются функции. Описание делегата в языке C# представляет собой описание еще одного частного случая класса.