Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Сериализация времени выполнения
Сериализация времени выполнения (runtime serialization) – это процесс преобразования объекта или графа связанных объектов в поток байтов. Десериализация – обратный процесс, заключающийся в восстановлении состояния объекта из потока байтов. Возможности сериализации используются при сохранении состояния объекта в файле, передаче объектов по сети, клонировании объектов. Платформа.NET обладает встроенным механизмом поддержки сериализации времени выполнения. Основные классы, связанные с сериализацией, размещены в пространствах имён с префиксом System.Runtime.Serialization. Например, сериализацию в двоичном формате обеспечивают классы из System.Runtime.Serialization.Formatters.Binary. При рассмотрении примеров сериализации будем использовать классы, описывающие одного студента и группу студентов: public class Student: IComparable< Student> { private string _name; private double _gpa;
public string Name { get { return _name; } set { _name = value; } }
public double GPA // Grade Point Average, средний балл { get { return _gpa; } set { _gpa = value; } }
public int CompareTo(Student other) { return GPA.CompareTo(other.GPA); } }
public class Group: Collection< Student> { private Student _bestStudent; private double _gpa;
public double GPA { get { return _gpa; } }
public Student BestStudent { get { return _bestStudent; } }
public double CalculateGroupGPA() { return _gpa = Items.Select(stud => stud.GPA).Average(); }
public Student FindTheBestStudent() { return _bestStudent = Items.Max(); } }
// создадим объекты классов Student и Group var group = new Group { new Student {Name = " Smirnov", GPA = 9.1}, new Student {Name = " Ivanova", GPA = 6.7}, new Student {Name = " Kuznetsov", GPA = 6}, new Student {Name = " Sokolov", GPA = 7.6}, new Student {Name = " Lebedeva", GPA = 9}}; Сериализация времени выполнения применима к объектам сериализуемых типов. Сериализуемый тип – это тип, помеченный атрибутом [Serializable][17], у которого все поля имеют сериализумый тип. Базовые типы платформы.NET являются сериализуемыми. Если планируется сериализация объекта group, необходимо добавить атрибут [Serializable] к классам Group и Student. Сериализация некоторых полей может не иметь смысла (например, эти поля вычисляются при работе с объектом или хранят конфиденциальные данные). Для таких полей можно применить атрибут [NonSerialized]. Изменим код классов Group и Student с учётом вышесказанного: [Serializable] public class Student: IComparable< Student> { // неизменившиеся элементы класса не показаны }
[Serializable] public class Group: Collection< Student> { // считаем, что поле _bestStudent является вычислимым [NonSerialized] private Student _bestStudent; // неизменившиеся элементы класса не показаны } Объекты сериализуемых типов можно сохранить в поток в различных форматах. В частности, платформа.NET поддерживает двоичный формат при помощи класса BinaryFormatter. Его экземплярный метод Serialize() принимает два аргумента – поток сериализации и сериализуемый объект: var formatter = new BinaryFormatter(); using (Stream s = File.Create(" group.dat")) { formatter.Serialize(s, group); } Метод Deserialize() класса BinaryFormatter выполняет десериализацию: var formatter = new BinaryFormatter(); using (Stream s = File.OpenRead(" group.dat")) { group = (Group) formatter.Deserialize(s); } Метод Deserialize() размещает объект в памяти и возвращает ссылку на него. При этом конструкторы не вызываются. Это может стать проблемой, если нужна особая инициализация объекта и восстановление несохраненных полей. Платформа.NET содержит атрибуты [OnSerializing], [OnSerialized], [OnDeserializing], [OnDeserialized], применимые к методам сериализуемого типа. Помеченные методы вызываются CLR автоматически до и после сериализации или десериализации соответственно. Метод, который обозначен одним из указанных атрибутов, должен принимать в качестве аргумента объект класса StreamingContext[18] и не возвращать значений. Каждый из атрибутов может применяться только к одному методу в типе. [Serializable] public class Group: Collection< Student> { [OnSerializing] private void BeforeSerialization(StreamingContext context) { CalculateGroupGPA(); } [OnDeserialized] private void AfterDeserialization(StreamingContext context) { FindTheBestStudent(); } // неизменившиеся элементы класса не показаны } Атрибут [OptionalField] применяется к полю и подавляет генерацию исключения при десериализации, если помеченное поле не найдено в потоке данных. Это позволяет сохранять «старые» объекты, затем модифицировать тип, расширяя состав его полей, и десериализовать данные в «новые» объекты типа. Если программиста не устраивает способ организации потока сериализуемых данных, он может повлиять на этот процесс, реализуя в сериализуемом типе интерфейс ISerializable: public interface ISerializable { void GetObjectData(SerializationInfo info, StreamingContext context); } Интерфейс ISerializable позволяет выполнить любые действия, связанные с формированием данных для сохранения. Метод GetObjectData() вызывается CLR автоматически при выполнении сериализации. Реализация метода подразумевает заполнение объекта SerializationInfo набором данных вида «ключ-значение», которые (обычно) соответствуют полям сохраняемого объекта. Класс SerializationInfo содержит перегруженный метод AddValue(), набор методов вида GetПримитивныйТип(), а также свойства для указания имени типа и сборки сериализуемого объекта. Если тип реализует интерфейс ISerializable, он должен содержать специальный private-конструктор, который будет вызывать CLR после выполнения десериализации. Конструктор должен иметь параметры типа SerializationInfo и StreamingContext. Рассмотрим пример реализации ISerializable в классе Student. [Serializable] public class Student: IComparable< Student>, ISerializable { void ISerializable.GetObjectData(SerializationInfo info, StreamingContext ctx) { info.SetType(typeof (Student)); info.AddValue(" Name", _name); info.AddValue(" GPA", (int) (_gpa*10)); }
private Student(SerializationInfo info, StreamingContext ctx) { _name = info.GetString(" Name"); _gpa = info.GetInt32(" GPA")/10.0; }
public Student() { }
// неизменившиеся элементы класса не показаны }
|