|
Глава 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г.
|