Глава.24 .Сериализация
m_version = num;
m_siInfo = null;
}
Каждый метод
AddValue
принимает в качестве параметра имя типа
String
и на-
бор данных. Обычно эти данные принадлежат к простым значимым типам, таким
как
Boolean
,
Char
,
Byte
,
SByte
,
Int16
,
UInt16
,
Int32
,
UInt32
,
Int64
,
UInt64
,
Single
,
Double
,
Decimal
и
DateTime
. Впрочем, методу
AddValue
можно передать ссылку на
тип
Object
, к примеру,
String
. После того как метод
GetObjectData
добавит всю
необходимую для сериализации информацию, управление возвращается модулю
форматирования.
ПриМеЧание
Добавлять.к.типу.информацию.сериализации.следует.только.с.помощью.одного.из.
перегруженных.методов.AddValue .Для.полей,.тип.которых.реализует.интерфейс.
ISerializable,.нельзя.вызывать.метод.GetObjectData .Чтобы.добавить.поле,.исполь-
зуйте.метод.AddValue;.модуль.форматирования.проследит.за.тем,.чтобы.тип.поля.
реализовал.ISerializable,.и.вызовет.метод.GetObjectData .Если.же.вы.решите.вызвать.
этот.метод.для.описанного.ранее.поля,.при.десериализации.потока.ввода-вывода.
модуль.форматирования.не.будет.знать,.что.он.должен.создать.новый.объект
На этом этапе модуль форматирования берет все добавленные к объекту
SerializationInfo
значения и сериализует их в поток ввода-вывода. Обратите
внимание, что методу
GetObjectData
передается еще один параметр: ссылка на
объект
System.Runtime.Serialization.StreamingContext
. Этот параметр игно-
рируется методом
GetObjectData
большинства типов, поэтому здесь мы на нем
останавливаться не станем, а рассмотрим его отдельно ближе к концу главы.
Итак, вы уже знаете, как задать всю необходимую для сериализации информа-
цию. Пришла пора рассмотреть процедуру десериализации. Извлекая объект из
потока ввода-вывода, модуль форматирования выделяет для него место в памяти
(вызывая статический метод
GetUninitializedObject
типа
System.Runtime.
Serialize.FormatterServices
). Изначально всем полям объекта присваивается
значение 0 или
null
. Затем модуль форматирования проверяет, реализует ли тип
интерфейс
ISerializable
. В случае положительного результата проверки модуль
пытается вызвать специальный конструктор, параметры которого идентичны па-
раметрам метода
GetObjectData
.
Для классов, помеченных модификатором
sealed
, этот конструктор рекомен-
дуется объявлять с модификатором
private
. Это предохранит код от случайного
вызова и повысит уровень безопасности. Также конструктор можно пометить мо-
дификатором
protected
, предоставив доступ к нему только производным классам.
Впрочем, модули форматирования могут вызывать его вне зависимости от того,
каким именно способом был объявлен конструктор.
Конструктор получает ссылку на объект
SerializationInfo
, содержащий все
значения, добавленные на этапе сериализации. Он может вызывать любые методы
683
Управление.сериализованными.и.десериализованными.данными
GetBoolean
,
GetChar
,
GetByte
,
GetSByte
,
GetInt16
,
GetUInt16
,
GetInt32
,
GetUInt32
,
GetInt64
,
GetUInt64
,
GetSingle
,
GetDouble
,
GetDecimal
,
GetDateTime
,
GetString
и
GetValue
, передавая им строку с именем, которое использовалось при сериали-
зации значения. Значения, возвращаемые этими методами, затем инициализируют
поля нового объекта.
При десериализации полей объекта нужно вызвать метод
Get
с тем же самым
типом значения, которое было передано методу
AddValue
в процессе сериализации.
Другими словами, если метод
GetObjectData
передал в метод
AddValue
значение
типа
Int32
, метод
GetInt32
должен вызываться для значения этого же типа. Если
значение в потоке ввода-вывода отличается от того, которое вы пытаетесь получить,
модуль форматирования попытается воспользоваться объектом
IFormatterConvert
для «приведения» к нужному типу значения в потоке ввода-вывода.
При конструировании объекта
SerializationInfo
ему передается объект типа,
реализующего интерфейс
IFormatterConverter
. Так как за конструирование от-
вечает модуль форматирования, он выбирает нужный тип
IFormatterConverter
.
Модули
BinaryFormatter
и
SoapFormatter
разработки Microsoft всегда конструиру-
ют экземпляр типа
System.Runtime.Serialization.FormatterConverter
. Выбрать
для этой цели другой тип
IFormatterConverter
не удастся.
Тип
FormatterConverter
использует статические методы класса
System.
Convert
для преобразования значений между базовыми типами, например из
Int32
в
Int64
. Но при необходимости преобразования между произвольными типами
FormatterConverter
вызывает метод
ChangeType
класса
Convert
для приведения
сериализованного (или исходного) типа к интерфейсу
IConvertible
. После это-
го вызывается подходящий интерфейсный метод. Следовательно, если объекты
сериализуемого типа требуется десериализовать как другой тип, нужно, чтобы
выбранный тип реализовывал интерфейс
IConvertible
. Обратите внимание, что
объект
FormatterConverter
используется только при десериализации объектов
и при вызове метода
Get
, тип которого не совпадает с типом значения в потоке
ввода-вывода.
Вместо одного из многочисленных методов
Get
специальный конструктор
может вызвать метод
GetEnumerator
, возвращающий объект
System.Runtime.
Serialization.SerializationInfoEnumerator
, при помощи которого можно
перебрать все значения внутри объекта
SerializationInfo
. Каждое из перечис-
ленных значений представляет собой объект
System.Runtime.Serialization.
SerializationEntry
.
Разумеется, никто не запрещает вам создавать собственные типы, производные
от типа, реализующего метод
GetObjectData
класса
ISerializable
, а также спе-
циальный конструктор. Если ваш тип реализует также интерфейс
ISerializable
,
для корректной сериализации и десериализации объекта ваши реализации метода
GetObjectData
и специального конструктора должны вызывать аналогичные
функции в базовом классе. В следующем разделе мы поговорим о том, как пра-
вильно определить тип
ISerializable
, базовый тип которого не реализует данный
интерфейс.
684
Do'stlaringiz bilan baham: |