Formatter сериализации
62C# и .NET --- Многопоточность и файлы --- Formatter сериализации
Как только типы сконфигурированы для участия в схеме сериализации .NET с применением необходимых атрибутов, следующий шаг состоит в выборе формата (двоичного, SOAP или XML) для сохранения состояния объектов. Перечисленные возможности представлены следующими классами:
BinaryFormatter
SoapFormatter
XmlSerializer
Тип 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 являются идеальным выбором, когда требуется гарантировать как можно более широкое распространение объектов.