Ранее мы посмотрели, как сохранять информацию в текстовые файлы, а также затронули сохранение несложных структур в бинарные данные. Но нередко подобных механизмов оказывается недостаточно особенно для сохранения сложных объектов. С этой проблемой призван справится механизм сериализации. Сериализация представляет процесс преобразования какого-либо объекта в поток байтов. После преобразования мы можем этот поток байтов или записать на диск или сохранить его временно в памяти. А при необходимости можно выполнить обратный процесс - десериализацию, то есть получить из потока байтов ранее сохраненный объект.
Чтобы объект определенного класса можно было сериализовать, надо этот класс пометить атрибутом Serializable:
[Serializable] class Person { public string Name { get; set; } public int Year { get; set; } public Person(string name, int year) { Name = name; Year = year; } }
При отстутствии данного атрибута объект Person не сможет быть сериализован, и при попытке сериализации будет выброшено исключение
SerializationException
.
Сериализация применяется к свойствам и полям класса. Если мы не хотим, чтобы какое-то поле класса сериализовалось, то мы его помечаем атрибутом NonSerialized:
[Serializable] class Person { public string Name { get; set; } public int Year { get; set; } [NonSerialized] public string accNumber; public Person(string name, int year, string acc) { Name = name; Year = year; accNumber = acc; } }
При наследовании подобного класса, следует учитывать, что атрибут Serializable автоматически не наследуется. И если мы хотим, чтобы производный класс также мог бы быть сериализован, то опять же мы применяем к нему атрибут:
[Serializable] class Worker : Person
Хотя сериализация представляет собой преобразование объекта в некоторый набор байтов, но в действительности только бинарным форматом она не ограничивается. Итак, в .NET можно использовать следующие форматы:
бинарный
SOAP
xml
JSON
Для каждого формата предусмотрен свой класс: для сериализации в бинарный формат - класс BinaryFormatter, для формата SOAP - класс SoapFormatter, для xml - XmlSerializer, для json - DataContractJsonSerializer.
Для классов BinaryFormatter и SoapFormatter сам функционал сериализации определен в интерфейсе IFormatter:
public interface IFormatter { SerializationBinder Binder { get; set;} StreamingContext Context { get; set;} ISurrogateSelector SurrogateSelector { get; set;} object Deserialize (Stream serializationStream); void Serialize (Stream serializationStream, object graph); }
Хотя классы BinaryFormatter и SoapFormatter по-разному реализуют данный интерфейс, но общий функционал будет тот же: для сериализации
будет использоваться метод Serialize
, который в качестве параметров принимает поток, куда помещает сериализованные данные (например,
бинарный файл), и объект, который надо сериализовать. А для десериализации будет применяться метод Deserialize
, который в качестве
параметра принимает поток с сериализованными данными.
Класс XmlSerializer не реализует интерфейс IFormatter и по функциональности в целом несколько отличается от BinaryFormatter и SoapFormatter, но и он также предоставляет для сериализации метод Serialize, а для десериализации Deserialize. И в этом плане очень легко при необходимости перейти от одного способа сериализации к другому.