
- •1. Язык программирования c# 3
- •2. Базовые элементы .Net Framework 67
- •3. ТЕхнология .Net Remoting 144
- •Введение
- •1. Язык программирования c#
- •1.1. Платформа .Net – обзор архитектуры
- •1.2. Язык c# - общие концепции синтаксиса
- •1.3. Система типов языка c#
- •1.4. Преобразования типов
- •1.5. Идентификаторы, ключевые слова и литералы
- •1.6. Объявление переменных, полей и констант
- •1.7. Выражения и операции
- •1.8. Операторы языка c#
- •1.9. Объявление и вызов методов
- •1.10. Массивы в c#
- •1.11. Работа с символами и строками в c#
- •1.12. Синтаксис объявления класса, Поля и методы класса
- •1.13. Свойства и индексаторы
- •1.14. Конструкторы класса и Жизненный цикл объекта
- •1.15. Наследование классов
- •1.16. Перегрузка операЦий
- •1.17. Делегаты
- •1.18. События
- •1.19. Интерфейсы
- •1.20. Структуры и перечисления
- •1.21. Пространства имен
- •1.22. Генерация и обработка исключительных ситуаций
- •1.23. Нововведения в языке c# 2.0
- •1.24. Обобщенные типы (generics)
- •2. Базовые элементы .Net Framework
- •2.1. Метаданные и механизм отражения
- •2.2. Пользовательские и встроенные атрибуты
- •2.3. Пространство имен system.Collections
- •2.4. Работа с файлами и директориями
- •2.5. Использование потоков данных
- •2.6. Сериализация
- •2.7. Сериализация объектов в нестандартном формате
- •2.8. Введение в xml
- •2.9. Работа с xml-документами в .Net framework
- •2.10. МНогопоточное программирование
- •2.11. Синхронизация потоков
- •2.12. Асинхронный вызов методов
- •2.13. Состав и взаимодействие сборок
- •2.14. Конфигурирование сборок
- •3. ТЕхнология .Net Remoting
- •3.1. Домены приложений
- •3.2. Архитектура .Net Remoting
- •3.3. Активация удаленных объектов и их время жизни
- •3.4. Программная настройка Remoting
- •3.5. Удаленные Объекты с клиентской активацией
- •3.6. Настройка Remoting при помощи конфигурационных файлов
- •3.7. Хостинг распределенных приложений
- •3.8. Объекты-сообщения
- •3.9. Пользовательские канальные приемники
- •4.1. Архитектура ado.Net
- •4.2. Учебная база cd Rent
- •4.3. Соединение с базой данных
- •4.4. Выполнение команд и запросов к базе данных
- •4.5. Чтение данных и объект DataReader
- •4.6. Параметризированные запросы
- •4.7. Рассоединенный набор данных
- •4.8. Заполнение Рассоединенного набора данных
- •4.9. Объект класса DataColumn – колонка таблицы
- •4.10. Объекты класса DataRow – строки таблицы
- •4.11. Работа с объектом класса DataTable
- •4.12. DataSet и схема рассоединенного набора данных
- •4.13. Типизированные DataSet
- •4.14. Поиск и фильтрация данных в DataSet
- •4.15. Класс DataView
- •4.16. СиНхронизация набора данных и базы
- •5.1. Архитектура и общие концепции asp.Net
- •5.2. Пример aspx-страницы. Структура страницы
- •5.3. Директивы страницы
- •5.4. Класс System.Web.Ui.Page. События страницы
- •5.5. Серверные элементы управления
- •5.6. Элементы управления Web Controls
- •5.7. Проверочные элементы управления
- •5.8. Списковые элементы управления
- •5.9. Связывание данных
- •5.11. Управление состояниями в web-приложениях
- •5.12. Кэширование
- •5.13. Безопасность в web-приложениях
- •5.14. Создание пользовательских элементов управления
- •Литература
2.6. Сериализация
Под сериализацией понимается действие, при котором данные объекта в памяти переносятся в байтовый поток для сохранения или передачи. Десериализация – это обратное действие, заключающееся в восстановлении состояния объекта по данным из байтового потока. При выполнении сериализации следует учитывать несколько нетривиальных моментов, например: сохранение полей объекта некоторого класса требует сохранения всех данных базовых классов; если объект содержит ссылки на другие объекты, то требуется сохранить данные всех объектов, на которые имеются ссылки.
Среда .NET Framework обладает развитым механизмом поддержки сериализации, включая поддержку сериализации в различных форматах. Основные классы, связанные с сериализацией, размещены в наборе пространств имен вида System.Runtime.Serialization.* и System.Xml.Serialization.*. Так, пространство имен System.Runtime.Serialization.Formatters.Binary обеспечивает поддержку сериализации в двоичном формате. Класс BinaryFormatter из этого пространства имен способен выполнить сериализацию графа объектов в поток при помощи метода Serialize() и десериализацию при помощи метода Deserialize().
Рассмотрим сериализацию на примере. Пусть имеется класс с информацией о студенте (имя, возраст, средний балл), а также класс с информацией о группе (список студентов и средний балл группы). Эти классы могут быть описаны следующим образом:
class Student {
public string Name;
public int Age;
public double MeanScore;
public Student(string Name, int Age, double MeanScore) {
this.Name = Name;
this.Age = Age;
this.MeanScore = MeanScore;
}
}
class Group {
public ArrayList GL = new ArrayList();
public double MSG;
public Student BestStudent;
public double CalcMSG() {
double sum = 0;
foreach(Student s in GL)
sum += s.MeanScore;
MSG = sum / GL.Count;
return MSG;
}
public Student FindTheBest() {
BestStudent = (Student)GL[0];
foreach(Student s in GL)
if (s.MeanScore > BestStudent.MeanScore)
BestStudent = s;
return BestStudent;
}
}
Допустим, что планируется осуществлять сериализацию объектов класса Group. Чтобы реализовать сериализацию пользовательского типа, он должен быть помечен специальным атрибутом – [Serializable]. Кроме этого, все поля такого типа также должны иметь этот атрибут. Данное замечание актуально в том случае, если поле имеет пользовательский тип, так как встроенные типы и большинство стандартных классов уже помечены как [Serializable]. В нашем случае мы должны добавить атрибут сериализации к классу Group и к классу Student. Сериализация некоторых полей может не иметь смысла (например, эти поля вычисляются при работе с объектом или хранят конфиденциальные данные). Для таких полей можно применить атрибут [NonSerialized]. Изменим код нашего примера с учетом вышесказанного:
[Serializable]
class Student {
. . .
}
[Serializable]
class Group {
public ArrayList GL = new ArrayList();
[NonSerialized] // Не надо сохранять – просто посчитаем
public double MSG;
. . .
}
Теперь все готово для выполнения сериализации. Метод Serialize() класса BinaryFormatter получает два параметра: поток, в который требуется выполнить сериализацию, и объект, который требуется сериализовать. Вот фрагмент кода, сериализующего объект класса Group, а затем выполняющего десериализацию:
// Нам понадобятся следующие пространства имен
using System;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
. . .
// Создаем группу и добавляем в нее несколько студентов
Group g = new Group();
g.GL.Add(new Student("Vova", 20, 4.5));
g.GL.Add(new Student("Ira", 20, 5));
g.GL.Add(new Student("Peter", 19, 4));
// Выводим некоторую информацию о группе
Console.WriteLine(g.CalcMSG());
Console.WriteLine(g.FindTheBest().Name);
// Создаем поток – это будет файл
Stream fs = new FileStream("data.dat", FileMode.Create);
// Создаем объект для сериализации в двоичном формате
BinaryFormatter fmt = new BinaryFormatter();
// Сериализуем и затем закрываем поток
fmt.Serialize(fs, g);
fs.Close();
// Теперь десериализация. Создаем поток
fs = new FileStream("data.dat", FileMode.Open);
// Десериализация. Обратите внимание на приведение типов
Group d = (Group)fmt.Deserialize(fs);
// Выводим информацию о группе
Console.WriteLine(d.CalcMSG());
Console.WriteLine(d.FindTheBest().Name);
Метод Deserialize() получает в качестве параметра поток, из которого десериализуется объект и возвращает объект типа object. В одном потоке можно сериализовать несколько различных объектов – главное, чтобы последовательность десериализации соответствовала сериализации.
Десериализацию удобно представлять как своеобразный вызов конструктора, так как результатом десериализации является ссылка на существующий объект. Однако если некоторые поля класса были помечены как [NonSerialized], то возможно после десериализации потребуется просчитать значения данных полей. Допустимое решение – реализовать в классе интерфейс IDeserializationCallback из пространства имен System.Runtime.Serialization. Данный интерфейс содержит единственный метод – OnDeserialization, который вызывается исполняемой средой автоматически после десериализации объекта. Используем интерфейс для класса Group:
[Serializable]
class Group : IDeserializationCallback {
public ArrayList GL = new ArrayList();
// Не будем сохранять средний балл и лучшего студента
[NonSerialized]
public double MSG;
[NonSerialized]
public Student BestStudent;
public double CalcMSG() { . . . }
public Student FindTheBest() { . . . }
// После десериализации просчитаем средний балл и
// найдем лучшего студента. Работа с параметром метода
// исполняемой средой на данный момент не поддерживается!
public void OnDeserialization(object o) {
CalcMSG();
FindTheBest();
}
}
Рассмотрим несколько примеров сериализации в различных форматах. Класс SoapFormatter из пространства имен System.Runtime.Serialization.Formatters.Soap обеспечивает сериализацию объекта в формате протокола SOAP (для использования данного пространства имен требуется подключить библиотеку system.runtime.serialization.formatters.soap.dll). Изменения в коде примера минимальны:
using System.Runtime.Serialization.Formatters.Soap;
. . .
// Создаем объект для сериализации в формате SOAP
SoapFormatter fmt = new SoapFormatter();
. . .
Файл в формате SOAP – это xml-файл с дополнительной информацией протокола SOAP. В .NET Framework можно выполнить сериализацию объектов в формате XML. Данный функционал обеспечивает класс XmlSerializer из пространства имен System.Xml.Serialization (файл System.Xml.dll). При XML-сериализации сохраняются данные объекта, доступные через public-свойства и поля. Кроме этого, сериализуемый класс должен иметь конструктор без параметров и являться public-классом.
Гибкая настройка XML-сериализации может быть выполнена при помощи атрибутов. Рассмотрим некоторые из атрибутов. Атрибут XmlRootAttribute применяется к классу и помогает определить корневой элемент в XML-файле. Поля и свойства, которые не должны сохраняться, помечаются атрибутом XmlIgnoreAttribute. Если класс агрегирует объекты других классов, то эти классы должны быть указаны при помощи атрибута XmlIncludeAttribute. Атрибут XmlAttributeAttribute используется, если элемент класса требуется сохранить в виде атрибута XML-тэга. Если класс агрегирует массив объектов, то настройка вида сохранения этого массива выполняется при помощи атрибутов XmlArrayAttribute и XmlArrayItemAttribute.
Рассмотрим пример XML-сериализации. Будем сохранять в формате XML данные классов Student и Group. При описании этих классов воспользуемся некоторыми атрибутами. Ниже представлен код программы, выполняющей создание объектов, сериализацию и десериализацию.
using System;
using System.Collections;
using System.IO;
using System.Xml.Serialization;
public class Student {
public string Name;
[XmlAttribute("Age")]
public int Age;
public double MeanScore;
public Student() { }
public Student(string Name, int Age, double MeanScore) {
this.Name = Name;
this.Age = Age;
this.MeanScore = MeanScore;
}
}
[XmlRoot("StudentGroup")]
[XmlInclude(typeof(Student))]
public class Group {
[XmlArray("GroupList")]
[XmlArrayItem("Student")]
public ArrayList GL = new ArrayList();
[XmlIgnore]
public double MSG;
public Group() { }
public double CalcMSG() {
double sum = 0;
foreach (Student s in GL)
sum += s.MeanScore;
MSG = sum / GL.Count;
return MSG;
}
}
class Program {
static void Main(string[] args) {
Group g = new Group();
g.GL.Add(new Student("Ivanov", 20, 6.0));
g.GL.Add(new Student("Petrov", 21, 7.0));
Stream fs= new FileStream("data.dat",FileMode.Create);
// Указываем тип того объекта, который сериализуем
XmlSerializer x = new XmlSerializer(typeof(Group));
// Сериализуем
x.Serialize(fs, g);
fs.Close();
// Восстанавливаем
fs = new FileStream("data.dat", FileMode.Open);
Group d = (Group)x.Deserialize(fs);
fs.Close();
}
}
XML-файл с сохраненной информацией выглядит следующим образом:
<?xml version="1.0"?>
<StudentGroup
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GroupList>
<Student xsi:type="Student" Age="20">
<Name>Ivanov</Name>
<MeanScore>6</MeanScore>
</Student>
<Student xsi:type="Student" Age="21">
<Name>Petrov</Name>
<MeanScore>7</MeanScore>
</Student>
</GroupList>
</StudentGroup>