12_C#_сериализация

advertisement
Сериализация (Serialization):
сохранение и восстановление объектов
 Сериализация - преобразование объекта или графа объектов в
линейную последовательность байт для сохранения на некотором
носителе или передачи по каналу связи для последующего
восстановления.
 Десериализация – восстановление объекта.
Классы BinaryFormatter и SOAPFormatter
 Сериализацию обеспечивают методы интерфейса IFormatter,
реализованные в классах-форматтерах:
System.Object
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
System.Runtime.Serialization.Formatters.Soap.SoapFormatter
 BinaryFormatter сохраняет объект в двоичном формате. При
использовании двоичного формата обеспечивается высокая
производительность.
 SoapFormatter сохраняет объект в XML-документе, оформленном по
стандарту SOAP (Simple Object Access Protocol). При использовании
SOAP формата обеспечивается межплатформенность.
 Интерфейс System.Runtime.Serialization.IFormatter :
public interface IFormatter
{
void Serialize( Stream serializationStream, object graph );
object Deserialize( Stream serializationStream );
…
}
Сериализация : общая схема
 Сериализация:
• cоздаем или получаем поток для сохранения объектов;
• создаем форматтер;
• вызываем метод Serialize для сериализации объектов в поток;
• не забыть закрыть поток!
Abc a = new Abc (3, “abc”);
Abc [] arr = new Abc[2] {new Abc(2, “efg”), new Abc(3, “xyz”)} ;
FileStream sW = File.Create("Data.bin");
BinaryFormatter binF = new BinaryFormatter();
binF.Serialize(sW, a);
binF.Serialize(sW, arr);
sW.Close();
Сериализация : общая схема -2
 Сериализовать можно только объекты классов (структур,
перечислений, делегатов), имеющих атрибут [Serializable].
 Если производный класс имеет атрибут [Serializable], базовый
класс также должен иметь этот атрибут. Все типы в графе объекта
также должны иметь атрибут [Serializable].
 Часть полей можно обозначить как [NonSerialized] (атрибут можно
прикрепить только к полю).
[Serializable]
class DataObject {
public int value;
[NonSerialized]
public string name; // Поле name не будет сохранено
…
// и восстановлено
}
Восстановление объектов : общая схема
 Десериализация:
• cоздаем или получаем поток для восстановления объектов;
• создаем форматтер;
• вызываем метод Deserialize для восстановления объектов из
потока;
• не забыть закрыть поток!
FileStream sR = File.OpenRead("Data.bin");
BinaryFormatter binR = new BinaryFormatter();
Abc da = (Abc) binR.Deserialize(sR);
Abc[] darr = (Abc[]) binR.Deserialize(sR);
sR.Close();
Нестандартная(custom) сериализация
 Можно внести изменения в стандартный процесс сериализации.
Для этого необходимо
• реализовать в классе, объекты которого сериализуются,
интерфейс ISerializable;
public interface ISerializable
{
void GetObjectData (SerializationInfo info, StreamingContext context);
}
• определить специальный конструктор
T(SerializationInfo info, StreamingContext context);
 Структура SerializationInfo содержит информацию об объекте, в том
числе имя типа и сборки.
 StreamingContext содержит информацию об источнике/приемнике
Нестандартная(custom) сериализация - 2
 Некоторые методы структуры SerializationInfo:
public
public
public
public
void
void
void
void
AddValue(
AddValue(
AddValue(
AddValue(
string
string
string
string
name,
name,
name,
name,
object value );
double value );
int value );
object value, Type type );
public
public
public
public
double GetDouble( string name );
int GetInt32( string name );
string GetString( string name );
object GetValue( string name, Type type );
Нестандартная(custom) сериализация - 3
 Метод GetObjectData явно сериализует данные объекта:
public virtual
void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("nt", nt);
info.AddValue("r", lst);
info.AddValue("name", name);
}
Конструктор вызывается при восстановлении объекта:
public CustomLAbc (SerializationInfo info, StreamingContext context)
{
nt = info.GetInt32("nt");
name = info.GetString ("name");
lst = (ArrayList) info.GetValue("r", typeof(ArrayList));
rData();
}
Интерфейс IDeserializationCallback
 Интерфейс IDeserializationCallback поддерживается всеми версиями
.NET Framework (1.0 и выше).
public interface IDeserializationCallback
{
void OnDeserialization(object sender);}
 Если тип реализует интерфейс IDeserializationCallback, метод
OnDeserialization будет вызван после десериализации объекта.
 В этом методе можно выполнить необходимую инициализацию,
например, присвоить значения полям объекта с атрибутом
[NonSerialized] (по умолчанию при десериализации объекта всем полям
с атрибутом [NonSerialized] присваиваются значения по умолчанию в
соответствии с типом).
События в BinaryFormatter
 Класс BinaryFormatter поддерживает четыре события, связанных с
сериализацией.
 Класс SOAPFormatter события не поддерживает.
 Схемы из статьи Juval Lowy “Format Your Way to Success with the
.NET Framework Versions 1.1 and 2.0”- MSDN Magazine, October 2004.
События в BinaryFormatter
Событие
Serializing
Serialized
Deserializing
Deserialized
Вызов
перед сериализацией
после сериализации
перед десериализацией
после десериализации
Атрибут
[OnSerializing]
[OnSerialized]
[OnDeserializing]
[OnDeserialized]
 Методы, которые работают как обработчики событий, должны иметь
атрибут и сигнатуру void <Method Name>(StreamingContext context);
Атрибуты [OnSerializ…] не наследуются.
 Атрибуты [OnSerializi…] можно одновременно прикрепить к
нескольким методам класса.
 К одному и тому же методу можно одновременно прикрепить и
атрибут [OnSerializing] и атрибут [OnSerialized], но нет простого способа
выяснить, для какого события был вызван метод.
Сериализация и версии сборки
 Для каждого сериализуемого объекта кроме его состояния
(значения сериализуемых полей) сохраняется полное имя сборки и
информация о версии сборки.
 При десериализации объекта загружается сборка и метаданные
типа.
 Если сборка, в которой находится сериализуемый тип, не имеет
строгого имени (strong name), форматеры полностью игнорируют
информацию о версии.
 Для сборок со строгим именем при сериализации и
десериализации версии сборок с типами должны быть согласованы.
Сериализация и версии сборки -2
 В классе BinaryFormatter определено свойство AssemblyFormat ,
которое дает возможность использовать только дружественное имя
сборки (friendly name) без информации о версии и открытом ключе
(public key token), даже если сборка имеет строгое имя:
public FormatterAssemblyStyle AssemblyFormat { get; set; }
Перечисление FormatterAssemblyStyle:
public enum FormatterAssemblyStyle
{ Full,
Simple
}
 Если значение свойства равно FormatterAssemblyStyle.Full, при
десериализации выполняется проверка версии сборки.
 Если значение равно FormatterAssemblyStyle.Simple, при
десериализации проверка версии сборки не выполняется.
Version Tolerant Serialization (VTS))
 В .NET Framework 1.x между метаданными типа, которые
используются при сериализации и десериализации, должно быть
полное соответствие.
 В .NET Framework 2.0 в класс BinaryFormatter внесены изменения,
которые допускают небольшие отличия в описании типа при
сериализации и десериализации.
 Это позволяет сохранить совместимость, если через некоторое
время сериализуемые типы немного модифицируются.
VTS: Толерантность по отношению к внешним или
неожидаемым данным
 В приведенном ниже примере
• при сериализации данных была использована новая версия
сборки с типом Address;
• при десериализации данных используется старая версия
сборки с типом Address;
 BinaryFormatter при десериализации пропустит поле CountryField
и не бросит исключение.
// Старая версия типа
[Serializable]
public class Address
{ string Street;
string City;
}
// Новая версия типа
[Serializable]
public class Address
{
string Street;
string City;
string CountryField;
}
VTS: Толерантность по отношению к
пропущенным данным
 В приведенном ниже примере
• при сериализации данных была использована старая версия
сборки с типом Address;
• при десериализации данных используется новая версия сборки
с типом Address;
 BinaryFormatter при десериализации присвоит полю CountryField
значение по умолчанию и не бросит исключение.
// Новая версия типа
// Старая версия типа
[Serializable]
public class Address
{
string Street;
string City;
}
[Serializable]
public class Address
{
string Street;
string City;
[OptionalField]
string CountryField;
}
Download