160 likes | 425 Views
Сериализация ( Serialization ) : сохранение и восстановление объектов. Сериализация - преобразование объекта или графа объектов в линейную последовательность байт для сохранения на некотором носителе или передачи по каналу связи для последующего восстановления.
E N D
Сериализация (Serialization):сохранение и восстановление объектов • Сериализация -преобразование объекта или графа объектов в линейную последовательность байт для сохранения на некотором носителе или передачи по каналу связи для последующего восстановления. • Десериализация – восстановление объекта.
Классы BinaryFormatter и SOAPFormatter • Сериализацию обеспечивают методы интерфейса IFormatter, реализованные в классах-форматтерах: System.ObjectSystem.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; publicinterface ISerializable { voidGetObjectData(SerializationInfoinfo, StreamingContextcontext); } • определить специальный конструктор T(SerializationInfo info, StreamingContext context); • Структура SerializationInfoсодержит информацию об объекте, в том числе имя типа и сборки. • StreamingContext содержит информацию об источнике/приемнике
Нестандартная(custom)сериализация - 2 • Некоторые методы структуры SerializationInfo: publicvoidAddValue( stringname, objectvalue ); publicvoidAddValue( stringname, doublevalue ); publicvoidAddValue( stringname, intvalue ); publicvoidAddValue( stringname, objectvalue, Typetype ); publicdoubleGetDouble( stringname ); publicintGetInt32( stringname ); publicstringGetString( stringname ); publicobjectGetValue( stringname, Typetype );
Нестандартная(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 • Методы, которые работают как обработчики событий, должны иметь атрибут и сигнатуру 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; string CountryField; } // Старая версия типа [Serializable] public class Address { string Street; string City; }
VTS: Толерантность по отношению к пропущенным данным • В приведенном ниже примере • при сериализации данных была использована старая версия сборки с типом Address; • при десериализации данных используется новая версия сборки с типом Address; • BinaryFormatter при десериализации присвоит полю CountryField значение по умолчанию и не бросит исключение. // Новая версия типа [Serializable] public class Address { string Street; string City; [OptionalField] string CountryField; } // Старая версия типа [Serializable] public class Address { string Street; string City; }