Разработка распределенных приложений в Microsoft.NET Framework

http://chapurin.kiev.ua/category/secret_zapurin/page/3/          

Сериализация графа объектов


В отличие от приложений на неуправляемом коде, приложения .NET Framework не обязательно выполняются в виде отдельных процессов, а могут существовать в пределах одного процесса операционной системы в своих собственных областях, называемых доменами приложения. Такие области можно рассматривать как некоторые логические процессы виртуальной машины CLR. Использование управляемого кода позволяет при этом гарантировать изоляцию приложений в пределах своих областей. При передаче между доменами приложений некоторого объекта для его класса должна быть определена процедура сериализации, которая позволяет сохранить состояние объекта в некотором внешнем хранилище (например, в файле, или в сообщении транспортного протокола) при помощи потоков ввода-вывода, и процедура десериализации, создающая копию объекта по сохраненному состоянию (рис. 4.1). Следует отметить, что в общем случае это могут быть объекты разных классов, и даже созданные в разных системах разработки приложений.


Рис. 4.1.  Сериализация и десериализация объекта

Задача сериализации объекта, включающего только поля из элементарных типов значений (наследников класса System.ValueType) и строк, не представляет принципиальных трудностей. Для такого объекта в ходе сериализации в поток записываются сами значения всех полей объекта. Однако в общем случае объект содержит ссылки на другие объекты, которые, в свою очередь, могут ссылаться друг на друга, образуя так называемый граф объектов (object graph). Сами ссылки не могут быть сохранены в потоке ввода-вывода, поэтому основной вопрос сериализации – это способ замены ссылок.

Граф объектов – ориентированный граф G = < V, E > , в котором вершины – это объекты (множество V), а ребра направлены от объектов, содержащие ссылки, на ссылаемые объекты (рис. 4.2).

public class SampleClass { public SampleClass fieldA = null; public SampleClass fieldB = null; } ... SampleClass root = new SampleClass(); SampleClass child1 = new SampleClass(); SampleClass child2 = new SampleClass(); root.fieldA = child1; root.fieldB = child2; child1.fieldA = child2; ...




Рис. 4.2.  Граф объектов

Наличие ссылки на объект B в объекте A есть принадлежность пары < A, B > множеству E. При рассмотрении графа все поля объектов, относящиеся к простым типам значениям и строкам, можно исключить из рассмотрения в силу тривиальности их сериализации. Хотя формально строки являются ссылочными типами, особенность реализации строк в CLI не дает возможность изменить уже созданную строку. Эта особенность позволяет тривиально обрабатывать строки при сериализации, сохраняя в потоке их содержимое.

Существует частный случай, когда сериализация выполняется тривиально. Для этого граф должен иметь вид так называемого ориентированного дерева. В каждую вершину дерева, отличную от корня, направлено единственное ребро, и существует единственная вершина, в которую не ведет ни одного ребра, называемая корнем. В таком случае сериализация может вестись от корня методом в глубину, а сериализация полей-ссылок выполняется аналогично сериализации полей значений – при обнаружении ссылки на объект вместо нее в хранилище помещаются значения полей ссылаемого объекта и некоторая дополнительная информация о типе объекта. Например, если существуют ребра < A, B1>, ... < A, Bn > , функция сериализации S для объекта A может быть определена как S(A) = < V(A), <S(B1),  ... S(Bn)>> , где функция V – значение полей значений и строк указанного объекта.

Проблема сериализации графа объектов связана с тем, что ссылка на один и тот же объект может быть значением поля у разных объектов (существуют ребра < A1, B> и < A2, B > ). Возможно также наличие циклов вида A 
 ...  
 A.

В этом случае в ходе сериализации объектам должны быть поставлены в соответствие некоторые идентификаторы, и в хранилище отдельно сохраняется список объектов, отмеченный идентификаторами, а при сериализации вместо ссылок записываются идентификаторы ссылаемых объектов. Если A1, ... An – все вершины графа, то его образом после сериализации будет множество {<idA1, S(A1)>, ... <idAn, S(An)>} , где S(A) определена как S(A) = < V(A), <idB1, ...


idBn> > , где B1, ... Bn – объекты, ссылки на которые непосредственно содержатся в объекте A. В программе роль идентификатора объекта выполняет его адрес, но вместо него обычно удобнее назначить некоторые идентификаторы в процедуре сериализации для более легкого чтения человеком полученного образа. В ходе сериализации нужно ввести список адресов уже записанных объектов, как для ведения списка идентификаторов, так и для обнаружения возможных циклов при обходе графа методом в глубину.

Следует отметить, что результат сериализации дерева легко представим в виде XML, когда содержимое каждого объекта представлено одним элементом с некоторым набором атрибутов и вложенных элементов. Поэтому при рассмотрения проблемы сериализации можно сформулировать рекомендацию, что классы, передаваемые между удаленными компонентами, должны являться корнем дерева объектов. В частном случае это дерево может быть вырожденным, то есть класс не содержит полей-ссылок вообще.


Содержание раздела







Forekc.ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий