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

Мне интересно, есть ли способ, которым я могу создать дерево/представление сериализованного графа объектов, и есть ли у кого-нибудь указатели? РЕДАКТИРОВАТЬ Цель состоит в том, чтобы, если по какой-то причине мы столкнемся с проблемой десериализации, мы могли фактически просмотреть/создать отчет о сериализованных данных, чтобы помочь нам определить причину проблемы, прежде чем приступать к отладке. код. Кроме того, я хочу расширить это в будущем, чтобы взять два потока (версия 1, версия 2) и выделить различия между ними, чтобы гарантировать, что мы случайно не удалим интересную информацию во время изменений кода. /РЕДАКТИРОВАТЬ

Традиционно мы использовали сериализацию Soap или XML, но они становятся слишком ограниченными для наших нужд, и двоичная сериализация обычно делает все, что нам нужно. Причина, по которой это не было принято, заключается в том, что гораздо сложнее просматривать сериализованное содержимое, чтобы помочь исправить проблемы с обновлением и т. д.

Итак, я начал пытаться создать представление сериализованной информации. Я могу сделать это из конструктора ISerializable в определенной степени:

public A(SerializationInfo info, StreamingContext context)
{}

Учитывая информацию о сериализации, я могу отразить член m_data и увидеть фактическое сериализованное содержимое. Проблема с этим подходом заключается в том,

  1. Он будет отображать только ветку от дерева, я хочу отобразить все дерево от корня и с этой позиции это не реально сделать.
  2. Это неудобное место для опроса информации, я хотел бы передать поток классу и выполнить там работу.

Я видел класс ObjectManager, но он работает с существующим графом объектов, тогда как мне нужно иметь возможность работать с потоком данных. Я просмотрел BinaryFormatted, который использует ObjectReader и __BinaryParser, подключаясь к ObjectManager (который, я думаю, будет иметь все содержимое, просто, возможно, в плоском списке), но чтобы воспроизвести это или вызвать все это через отражение (2 из этих 3 классов являются внутренними) похоже, довольно много работы, поэтому мне интересно, есть ли лучший подход.


person Ian    schedule 10.11.2011    source источник
comment
Почему сериализация XML «становится слишком ограниченной для наших нужд»? Для бинарных компонентов, например. изображения, вы можете использовать кодировку base64, которая относительно эффективна. Если вам нужно сериализовать огромные объекты, стоит использовать двоичный код, но затем создайте свой собственный редактор для его чтения.   -  person zmilojko    schedule 10.11.2011
comment
Сериализация XML оказывается слишком медленной из-за большого количества сериализуемой информации, в прошлом у нас было несколько проблем с кодировкой, другая половина нашего продукта — ISerializable. Мы хотели бы перейти к общему формату, а XML до сих пор доставлял нам слишком много головной боли.   -  person Ian    schedule 10.11.2011
comment
можно уточнить вопрос, что вы ищете? Лучший формат или инструмент для чтения двоичных сериализованных объектов? Потому что очевидный ответ на ваш вопрос: десериализуйте его и покажите в своем приложении.   -  person zmilojko    schedule 10.11.2011
comment
вы смотрели на protobuf? protobuf-net, если быть точным. Это невероятно быстро и позволяет проводить анализ более высокого уровня.   -  person Polity    schedule 10.11.2011
comment
@zmilojko: я обновил свой вопрос, он больше о том, когда мы не можем десериализовать поток по какой-то причине, и мы хотим выяснить, почему.   -  person Ian    schedule 10.11.2011
comment
@Polity: я просмотрел protobuf, но мы пытались сами реализовать пользовательские сериализаторы, и это было головной болью. Когда я читал о protobuf ранее, казалось, что есть несколько вещей, которые он не поддерживает, и мне не нравится соглашение о целочисленных атрибутах, я полагаю, что это затруднит правильную обработку обновлений и т. д. в большей кодовой базе. Я думаю, что для меньшего и менее динамичного графа объектов это было бы здорово.   -  person Ian    schedule 10.11.2011
comment
Я сбит с толку тем, что «когда мы не можем десериализовать». По крайней мере, по моему опыту, все стандартные сериализаторы работают одинаково. Так что заставьте его работать с XML (даже если он медленный), и он будет работать с бинарным. Если вы внедряете свои собственные, приготовьтесь страдать! Но ответ на ваш вопрос будет таким: создайте бинарный парсер. И именно поэтому я люблю .NET: мне не нужно делать это самому, в .NET это уже реализовано.   -  person zmilojko    schedule 10.11.2011
comment
@zmilojko: Я считаю, что вы путаете XML с Soap. Мыло устарело, а XML не обрабатывает множество простых случаев (словари, универсальные шаблоны и т. д.). Следовательно, Binary — самый простой выбор. Ошибки в сериализации, как правило, возникают из-за ошибок в коде или когда ISerializable не реализован, и мы хотим явно написать его, возможность видеть содержимое графа объектов и имена элементов из примера потока значительно упрощает записывать.   -  person Ian    schedule 10.11.2011


Ответы (2)


Вы можете поместить List<Child class> в каждый родительский класс (даже если там то же самое)

и когда вы создаете дочерний элемент, вы сразу же помещаете его в этот список или, что еще лучше, объявляете его при добавлении в список

Например

ListName.Add(new Child(Constructer args));

Используя это, вы бы сериализовали их как один файл, который содержит иерархию объектов и самих объектов.

Если родительский и дочерний классы одинаковы, нет причин, по которым у вас не может быть динамической и многоуровневой иерархии.

person BananaPoop    schedule 03.01.2012

Чтобы добиться того, что вы описываете, вам придется десериализовать весь граф объектов из потока, не зная типа, из которого он был сериализован. Но это невозможно, потому что сериализатор не хранит такую ​​информацию. AFAIK работает следующим образом. Предположим, у вас есть несколько типов:

class A { bool p1 }
class B { string p1; string p2; A p3}
// instantiate them:
var b = new B { p1 = "ppp1", p2 = "ppp2", p3 = new A { p1 = true} };

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

[B:[string:ppp1][string:ppp2][A:[bool:true]]]

Видите ли, здесь есть только значения и их типы. Но порядок неявный - как написано. Итак, если вы измените свой объект B, предположим,

class B { A p1; string p3; string p3;}

Serialzer потерпит неудачу, потому что он попытается присвоить экземпляр строки (которая была сериализована первой) указателю на A. Вы можете попытаться перепроектировать, как работает двоичная сериализация, тогда вы сможете создать динамическое дерево сериализованных объектов. Но это потребует значительных усилий.

Для этой цели я бы создал класс, подобный этому:

class Node
{
    public string NodeType;
    public List<Node> Children;
    public object NodeValue;
}

Затем, пока вы будете читать из потока, вы можете создать эти узлы, воссоздать все сериализованное дерево и проанализировать его.

person Vladimir Perevalov    schedule 10.11.2011
comment
Вы уверены, что это так работает? Из того, что я просмотрел, я подумал, что двоичный сериализатор действительно сериализует информацию о типе... Если вы посмотрите, например, на сериализацию Soap, полные имена типов сборок содержатся в Soap Xml. - person Ian; 10.11.2011