Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Базовые технологии платформы .NET.pdf
Скачиваний:
65
Добавлен:
11.05.2015
Размер:
1.81 Mб
Скачать

21. Сериализация времени выполнения

Сериализация времени выполнения (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

87

{

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 = "Sokolov", GPA = 7.6},

new Student

{Name = "Lebedeva", GPA = 9}};

Сериализация времени выполнения применима к объектам сериализуемых типов. Сериализуемый тип – это тип, помеченный атрибутом [Serializable]1, у которого все поля имеют сериализуемый тип. Базовые типы платформы .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;

//неизменившиеся элементы класса не показаны

}

1 Подробно о синтаксисе применения атрибутов и операторе typeof рассказывается далее.

88

Объекты сериализуемых типов можно сохранить в поток в различных форматах. В частности, платформа .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 автоматически до и после сериализации или десериализации соответственно. Метод, который обозначен одним из указанных атрибутов, должен принимать в качестве аргумента объект класса StreamingContext1 и не возвращать значений. Каждый из атрибутов может применяться только к одному методу в типе.

[Serializable]

public class Group : Collection<Student>

{

[OnSerializing]

private void BeforeSerialization(StreamingContext context)

{

CalculateGroupGPA();

}

[OnDeserialized]

private void AfterDeserialization(StreamingContext context)

{

FindTheBestStudent();

}

// неизменившиеся элементы класса не показаны

}

1 Класс StreamingContext описывает контекст потока сериализации. Основным свойством класса является State, принимающее значения из перечисления StreamingContextStates.

89

Атрибут [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() { }

// неизменившиеся элементы класса не показаны

}

90