Опубликован: 11.05.2007 | Доступ: свободный | Студентов: 1706 / 243 | Оценка: 4.36 / 4.25 | Длительность: 16:06:00
Лекция 4:

Сериализация объектов. Способы сериализации в .NET Framework

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >

4.3. Класс сериализации XmlSerializer

Класс System.Xml.Serialization.XmlSerializer реализует открытый текстовый метод сериализации, использующий XML в качестве базового формата хранения и схемы XML для спецификации документа с результатом сериализации. Данный класс используется, в частности, в веб-службах ASP.NET и при работе с очередями сообщений MSMQ. Класс XmlSerializer порождает представление объекта на языке XML, легко читаемое и модифицируемое человеком или программами. Класс XmlSerializer позволяет управлять соответствием класса и схемы XML при помощи специальных атрибутов полей классов. Благодаря открытой спецификации формата хранения, при использовании XmlSerializer возможна десериализация в тип данных, отличный от исходного, как и написание взаимодействующих компонент на основе средств разработки.

Схема XML может быть получена из описания класса, если имеется информация о всех типах объектов, которые могут содержаться во всех полях каждого класса. В частности, это означает что для класса общего вида ( generic ) XML-схема в общем случае не может быть получена. Однако и для конкретных классов самого описания типа недостаточно для создания схемы. Например, в поле вида IVehicle vehicleValue может содержаться объект любого класса, реализующий интерфейс IVehicle. Данная проблема решается в CLI благодаря системе атрибутов. Например, используя атрибут System.XML.Serialization.XmlAttribute , можно перечислить все возможные типы объектов данного поля. Хотя такой подход не идеален с точки зрения объектно-ориентированного подхода, он дает возможность строго специфицировать содержимое XML-файла. Ниже приведен пример использования атрибута XmlAttribute.

[System.XML.Serialization.XmlAttribute(typeof(Car)),
System.XML.Serialization.XmlAttribute(typeof(Bike)),
System.XML.Serialization.XmlAttribute(typeof(LongTruck))]
IVehicle vehicleValue;

Таким образом, при использовании некоторых дополнительных метаданных, для классов CLI может быть построена соответствующая им схема XML, которая будет корректной для организованного древовидно графа объектов.

Используемый классом XmlSerializer метод сериализации имеет ряд недостатков. Во-первых, он не является универсальным: сериализуемый им граф объектов не может содержать циклы. Во-вторых, он полагает, что граф объектов является деревом и записывает значение полей объекта на место их ссылки. В результате десериализации создаются столько копий объектов, сколько в соответствующем графе в него входило ребер (рис. 4.3). Поскольку на этапе построения XML-схемы нет никакой информации о каких-либо объектах, а только описания полей и свойств классов, то предполагается, что на каждый объект сериализуемого графа, отличный от его корня, существует единственная ссылка в поле какого-либо другого объекта этого же графа.

Применение XmlSerializer к произвольному графу объектов

Рис. 4.3. Применение XmlSerializer к произвольному графу объектов

Наибольшей трудностью при использовании класса XmlSerializer являются предъявляемые им требования к сериализуемым классам. В .NET Framework 2.0 XmlSerializer позволяет сериализовать публичные классы, имеющие конструктор без параметров типа public и отвечающие одному из следующих требований.

  1. Класс реализует интерфейс IXMLSerializable. В этом случае XmlSerializer просто использует при сериализации методы класса GetSchema, ReadXml, WriteXml.
  2. Класс реализует интерфейс System.Collections.IEnumerable, но не реализует ICollection и содержит публичный метод Add c единственным параметром, имеющим тип, совпадающий с типом результата свойства IEnumerator.Current метода GetEnumerator сериализуемого объекта. Такой класс сериализуется через вызовы класса IEnumerator, возвращаемого методом GetEnumerator, а его публичные поля и свойства не сериализуются.
  3. Класс реализует интерфейс System.Collections.ICollection, но не реализует IEnumerable. Для такого класса осуществляется сериализация только свойства Item и публичных полей, реализующих интерфейс ICollection. Другие публичные поля и свойства не сериализуются.
  4. Класс реализует интерфейсы ICollection и IEnumerable, имеет публичное индексированное свойство Item c целым индексом и публичное целое свойство Count. Тип, принимаемый методом Add, должен быть типом свойства Item или одним из его предков. Другие публичные поля и свойства не сериализуются.
  5. Класс не реализует ни один из интерфейсов IXMLSerializer, IEnumerable, ICollection и имеет атрибут System.SerializableAttribute. В этом случае будут сериализованы публичные свойства и поля класса с учетом специальных атрибутов, управляющих процессом сериализации.

Подлежащие сериализации публичные свойства должны иметь реализацию обоих методов, get и set. Кроме того, если класс не использует собственную процедуру сериализации, то он не должен иметь свойств или полей типа интерфейс или многомерных массивов, вместо них следует использовать вложенные массивы.

// недопустимо в сериализуемом автоматически классе
public int[,] data = new int[2,2];

К сожалению, классы FCL, реализующие интерфейс IDictionary, не удовлетворяют этим требованием (их метод Add имеет два параметра). Поэтому главным практическим недостатком XmlSerializer является неспособность самостоятельно обрабатывать типы, реализующие интерфейс System.Collections.IDictionary, использующиеся для хранения пар ключзначение. В частности, к ним относится популярный класс System.Collections.Hashtable. Однако можно создать собственный класс, включающий в себя поле типа Hashtable и реализующий интерфейс IXmlSerializable. XMLSerializer может обрабатывать следующие важные на практике классы из FCL:

  • System.XML.XmlNode и его наследники System.XML.XmlDocumеnt и System.XML.XmlElement, причем сериализация XML-документа является этим же XML-документом (с точностью до форматирования, не влияющего на содержимое документа);
  • класс System.Data.Dataset ;
  • классы общего вида ( generic classes ) из System.Collections.Generic, такие как List или Queue, кроме Dictionary и SortedDictionary.

Как было указанно ранее, для большинства классов можно использовать описанные в System.Xml.Serialization атрибуты сериализации, которые позволяют установить связь между полями класса и атрибутами или элементами XML, отвечающими ему. Также можно использовать атрибут NonSerializedAttribute для публичных полей или свойств, не подлежащих сериализации.

< Лекция 3 || Лекция 4: 1234 || Лекция 5 >