Formatter сериализации

62

Как только типы сконфигурированы для участия в схеме сериализации .NET с применением необходимых атрибутов, следующий шаг состоит в выборе формата (двоичного, SOAP или XML) для сохранения состояния объектов. Перечисленные возможности представлены следующими классами:

Тип BinaryFormatter сериализует состояние объекта в поток, используя компактный двоичный формат. Этот тип определен в пространстве имен System.Runtime.Serialization.Formatters.Binary, которое входит в сборку mscorlib.dll. Таким образом, чтобы получить доступ к этому типу, необходимо указать следующую директиву using:

// Получить доступ к BinaryFormatter в mscorlib.dll
using System.Runtime.Serialization.Formatters.Binary;

Тип SoapFormatter сохраняет состояние объекта в виде сообщения SOAP (стандартный XML-формат для передачи и приема сообщений от веб-служб). Этот тип определен в пространстве имен System.Runtime.Serialization.Formatters.Soap, находящемся в отдельной сборке. Поэтому для форматирования графа объектов в сообщение SOAP необходимо сначала установить ссылку на System.Runtime.Serialization.Formatters.Soap.dll, используя диалоговое окно Add Reference (Добавить ссылку) в Visual Studio 2010 и затем указать следующую директиву using:

// Необходима ссылка на System.Runtime.Serialization.Formatters.Soap.dll!
using System.Runtime.Serialization.Formatters.Soap;

И, наконец, для сохранения дерева объектов в документе XML имеется тип XmlSerializer. Чтобы использовать этот тип, нужно указать директиву using для пространства имен System.Xml.Serialization и установить ссылку на сборку System.Xml.dll. К счастью, шаблоны проектов Visual Studio 2010 автоматически ссылаются на System.Xml.dll, так что достаточно просто указать соответствующее пространство имен:

// Определено внутри System.Xml.dll
using System.Xml.Serialization;

Интерфейсы IFormatter и IRemotingFormatter

Независимо от того, какой форматер выбран, имейте в виду, каждый из них наследуется непосредственно от System.Object, так что они не разделяют общего набора членов от какого-то базового класса сериализации. Однако типы BinaryFormatter и SoapFormatter поддерживают общие члены через реализацию интерфейсов IFormatter и IRemotingFormatter (как ни странно, XmlSerializer не реализует ни одного из них).

В System.Runtime.Serialization.IFormatter определены основные методы Serialize() и Deserialize(), которые выполняют черновую работу по перемещению графов объектов в определенный поток и обратно. Помимо этих членов в 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);
}

Интерфейс System.Runtime.Remoting.Messaging.IRemotingFormatter (который внутри полагается на уровень удаленного взаимодействия .NET Remoting) перегружает члены Serialize() и Deserialize() в манере, более подходящей для распределенного сохранения. Обратите внимание, что интерфейс IRemotingFormatter унаследован от более общего интерфейса IFormatter:

public interface IRemotingFormatter : IFormatter
{
   object Deserialize(Stream serializationStream, HeaderHandler handler);
   void Serialize(Stream serializationStream, object graph,
      Header[] headers);
}

Хотя взаимодействовать с этими интерфейсами не понадобится в большинстве сценариев сериализации, вспомните, что полиморфизм на базе интерфейсов позволяет подставлять экземпляры BinaryFormatter или SoapFormatter там, где ожидается IFormatter.

Точность типов среди форматеров

Наиболее очевидное отличие между тремя форматерами связано с тем, как граф объектов сохраняется в потоке (двоичном, SOAP или XML). Следует знать также о некоторых более тонких отличиях, в частности — каким образом форматеры добиваются точности типов (type fidelity).

Когда используется тип BinaryFormatter, он сохраняет не только данные полей объектов из графа, но также полное квалифицированное имя каждого типа и полное имя определяющей его сборки (имя, версия, маркер общедоступного ключа и культура). Эти дополнительные элементы данных делают BinaryFormatter идеальным выбором, когда необходимо передавать объекты по значению (т.е. полные копии) между границами машин для использования в .NET-приложениях.

Форматер SoapFormatter сохраняет трассировки сборок-источников за счет использования пространства имен XML. Например, вспомните тип Person, определенный в предыдущей статье. Если понадобится сохранить этот тип в сообщении SOAP, вы обнаружите, что открывающий элемент Person квалифицирован сгенерированным параметром xmlns. Взгляните на следующее частичное определение, обратив особое внимание на пространство имен XML под названием a1:

<a1:Person id="ref-1" xmlns:a1=
   "http://schemas.microsoft.com/clr/nsassem/SimpleSerialize/MyApp%2C%20
   Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
   <isAlive>true</isAlive>
   <personAge>21</personAge>
   <fName id="ref-3"></fName>
</a1:Person>

Однако XmlSerializer не пытается предохранить точную информацию о типе, и потому не записывает его полного квалифицированного имени или сборки, в которой он определен. Хотя на первый взгляд это может показаться ограничением, причина состоит в открытой природе представления данных XML. Ниже показано возможное XML-представление типа Person:

<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2 001/XMLSchema">
      <isAlive>true</isAlive>
      <PersonAge>2l</PersonAge>
      <FirstName />
</Person>

Если необходимо сохранить состояние объекта так, чтобы его можно было использовать в любой операционной системе (Windows ХР, Mac OS X и различных дистрибутивах Linux), на любой платформе приложений (.NET, Java Enterprise Edition, COM и т.п.) или в любом языке программирования, придерживаться полной точности типов не следует, поскольку нельзя рассчитывать, что все возможные адресаты смогут понять специфичные для .NET типы данных. Учитывая это, SoapFormatter и XmlSerializer являются идеальным выбором, когда требуется гарантировать как можно более широкое распространение объектов.

Пройди тесты
Лучший чат для C# программистов