Читать «ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание» онлайн - страница 407
Эндрю Троелсен
Более глубокий взгляд на сериализацию объектов
Перед тем как рассмотреть различные способы настройки параметров процесса сериализации, было бы полезно выяснить, что при этом происходит "за кулисами". Когда тип BinaryFormatter выполняет сериализацию объектного графа, этот тип отвечает за передачу в указанный поток следующей информации:
• абсолютных имен объектов графа (например, MyApp.JamesBondCar);
• имени компоновочного блока, определяющего объектный граф (например, MyApp.exe);
• экземпляра класса SerializationInfo, содержащего все данные, поддерживаемые членами объектного графа.
В процессе реконструкции объекта тип BinaryFormatter использует ту же информацию, извлеченную из соответствующего потока, для построения абсолютно точной копии объекта.
Замечание. Напомним, что SoapFormatter и XmlSerializer не сохраняют абсолютное имя типа и имя определяющего компоновочного блока. Эти типы заботятся только о сохранении открытых полей данных.
Общую картину можно представлять в виде диаграммы, показанной на рис. 17.3.
Рис. 17.3 Схема процесса сериализации
Кроме перемещения необходимых данных в поток и извлечения их из потока, средство форматирования (форматтер) анализирует члены объектного графа на наличие следующих элементов инфраструктуры.
• Выясняется, обозначен ли объект атрибутом [Serializable]. Если нет, то генерируется исключение SerializationException.
• Если объект обозначен атрибутом [Serializable], то выясняется, реализует ли объект интерфейс ISerializable. Если да, то для объекта вызывается GetObjectData().
• Если объект не реализует ISerializable, используется типовой процесс сериализации, сохраняются все поля, не обозначенные атрибутом [NonSerialized].
Вдобавок к выявлению поддержки типом интерфейса ISerializable, форматтеры (в .NET 2.0) отвечают также за выявление поддержки соответствующими типами членов, обозначенных атрибутами [OnSerializing], [OnSerialized], [OnDeserializing] или [OnDeserialized]. Роль этих атрибутов будет обсуждаться позже, a пока что мы рассмотрим роль ISerializable.
Настройка параметров сериализации с помощью ISerializable
Объекты, обозначаемые атрибутом [Serializable], имеют возможность реализовать интерфейс ISerializable. В этом случае вы можете "участвовать" в процессе сериализации, выполняя любое предварительное или последующее форматирование данных. Указанный интерфейс очень прост, поскольку он определяет единственный метод, GetObjectData().
// Для настройки процесса сериализации реализуйте ISerializable.
public interface ISerializable {
void GetObjectData(SerializationInfo info, StreamingContext context);
}
Метод GetObjectData() вызывается форматтером в процессе сериализации автоматически. Реализация этого метода предоставляет через входной параметр SerializationInfo серию пар имен и значений, которые (обычно) соответствуют полям данных того объекта, который следует сохранить. Тип SerializationInfo определяет перегруженный метод AddValue(), имеющий множество вариаций, а также небольшой набор свойств, которые позволяют читать и устанавливать имя типа, имя определяющего компоновочного блока и значение счетчика членов. Вот фрагмент соответствующего программного кода.