Глава 6 Сериализация объектов
Параграф 1. О сериализации объектовСериализация - процесс преобразования некоторого объекта (класса) в последовательность байтов с целью сохранения в памяти (базе данных, файле), отправки объекта удаленному приложению посредством веб-службы, передача объекта из одного домена в другой, передача объекта через брандмауэр в виде XML-строки и хранение информации о безопасности или конкретном пользователе, используемой несколькими приложениями. Сериализация - процесс двунаправленный и имеет целью не только сохранить и передать в удобном виде данных, но и возможность воссоздать его при необходимости в виде исходного объекта. Обратный процесс называется десериализацией. Пространство имен System.Runtime.Serialization содержит классы, необходимые для сериализации и десериализации объектов. Для того, что бы объект мог быть сериализован, он должен быть помеченным как сериализуемый объект: [Serializable] Кроме того, для того, чтобы сериализация стала возможной необходимо также объявление пространств имен: using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using System.IO; Дополнительно в объекте часть информации может требовать или не требовать сохранения и дальнейшего восстановления, в этом случае применяется метки-атрибуты [SerializableAttribute] и [NonSerializedAttribute]. Cериализуемая информация содержит не только данные, но и сведения о типе объекта (версию, язык и региональные параметры, а также имя сборки). Основную информацию по выполнению сериализации проводит специальный объект - Formatter. Как мы уже отмечали, различают двоичную и XML-сериализацию. При XML-сериализации информация сериализуется в XML-поток. XML-сериализация может также использоваться для сериализации объектов в потоки XML, которые соответствуют спецификации SOAP (Simple Object Access Protocol — простой протокол доступа к объектам). SOAP - это протокол, основанный на XML и созданный специально для передачи вызовов процедур с использованием XML. Подробно мы будем говорить о XML-сериализации, когда руки автора доберутся до Web-сервисов. А пока познакомимся с двоичной сериализацией в файлы. И последнее замечание перед приведением примера использования сериализации, мы отмечали, что сериализованная информация хранит версию приложения и ряд других его атрибутов. Один из способов обойти это - настраиваемая сериализация, когда можно указать какие объекты будут сериализованы, и как будет производиться сериализация. Существует способ обхода этого варианта, связанные с сериализацией конструктора и некоторыми другими тонкостями, которые выходит за рамки статьи. Впервые я использовал сериализацию при создании Русско-японского переводчика с целью хоть по минимуму защить труд автора словаря - вытащить из двоичного исходного файла Excel исходный документ словаря практически невозможно. Вот на этом примере я и покажу механизм двоичной сериализации. Параграф 2. Пример создания класса для двоичной сериализацииИтак, создадим пустое пока решение (например, с именем myProject) приложения и добавим к нему класс, который будет выполнять функции словаря. В окне "Solutation Explorer" (Меню Viev | Solutation Explorer) выполним правый клик мышкой на файле проекта и добавим новую опцию (Рис.1.).
Рис.1 Создание приложения и добавление класса для сериализации
Рис.2 Создание приложения и добавдение класса для сериализации В код класса, который мы хотим сделать сериализуемым добавим помеченный как сериализуемый объект - [Serializable]: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace myProject { [Serializable] class dictionary { } } В класс dictionary добавим методы, делающие класс словарем, например Hashtable, предоставляющую коллекцию пар ключ/значение, которые упорядочены по хэш-коду ключа и которая собственно будет хранить словарь. При добавлении элемента в коллекцию Hashtable он помещается в определенный сегмент в зависимости от хэш-кода ключа. В дальнейшем поиск ключа осуществляется только в определенном сегменте с использованием хэш-кода ключа. Таким образом, в значительной степени уменьшается количество операций сравнения ключей, которое требуется для нахождения элемента. Итак, первым добавим: private Hashtable hashTable = new Hashtable(); Далее понадобятся такие методы, как число значений, проверки наличия слова в словаре, метод перевода слова, добавления и удаления записей в словарь: public int Count { get { return hashTable.Count; } } public bool Contains(string word) { return hashTable.Contains(word); } public string Translate(string word) { return (string)hashTable[word]; } public void Add(string key, string value) { if(!hashTable.Contains(key)) hashTable.Add(key, value); } public void Remove(string key) { if(hashTable.Contains(key)) hashTable.Remove(key); } //Здесь можно добавить другие методы .................................. } Параграф 3. Работа по сериализации и десериализации классаПервым в основном приложении добавляем необходимые пространства имен, а именно: using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using System.IO; И соответственно объявляем потомка созданного класса, и делаем из него рабочий класс - workDict=new workDict(); : using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using System.IO; namespace myProject { public partial class Form1 : Form { public dictionary workDict = null; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { workDict=new workDict(); } Далее можно пользоваться методами добавления и удаления данных в словарь, описанных выше. Осталось сохранить словарь в сериализованном виде и загрузить вновь словарь в память. Запись можно выполнить так (sCurDir - текущая директория старта приложения - там мы будем размещать и словарь): private void vSave() { string s = string.Empty; BinaryFormatter bf = null; string sDicPath = sCurDir + @"\Dictionary.dct"; bool fYes = false; using (FileStream fs = File.Create(sDicPath)) { try { bf = new BinaryFormatter(); bf.Serialize(fs, workDict); fYes = true; } catch (SerializationException ex) { s = ex.Message; MessageBox.Show(s, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (IOException ex1) { s = ex1.Message; MessageBox.Show(s, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { if (fs != null) fs.Close(); if (bf != null) bf = null; } } if (fYes) { s = "Сохранен словарь объемом " + Convert.ToString(workDict.Count) + "пар слов (словосочетаний, фраз)."; MessageBox.Show(s, "Информация!", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { s = "Словарь не сохранен из-за ошибки!"; MessageBox.Show(s, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } Для загрузки сериализованного файла словаря можно воспользоваться следующей функцией: private void vDicLoad() { string s = string.Empty; string s1 = string.Empty; bool fYes = false; BinaryFormatter bf = null; FileStream fs = null; try { if (workDict == null) { workDict = new Dictionary(); } if (File.Exists(sCurDir + @"\Dictionary.dct")) { fs = new FileStream(sCurDir + @"\Dictionary.dct", FileMode.Open, FileAccess.Read); bf = new BinaryFormatter(); workDict = bf.Deserialize(fs) as Dictionary; fYes = true; } } catch (SerializationException ex) { label1.ForeColor = Color.Red; label1.Text = ex.Message; } catch (IOException ex1) { label1.ForeColor = Color.Red; label1.Text = ex1.Message; } finally { if (fs != null) fs.Close(); if (bf != null) bf = null; } if (fYes) { s = "Загружен словарь объемом " + Convert.ToString(workDict.Count) + " записей."; MessageBox.Show(s, "Информация!", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { s = "Словарь пока пуст. Вы можите приступить к его заполнению"; MessageBox.Show(s, "Информация!", MessageBoxButtons.OK, MessageBoxIcon.Information); } } Вот и все тонкости работы по двоичной сериализации и десиреализации, приведенные на кокретном примере работы со словарем. Молчанов Владислав 1.05.2008г.
|