Сериализация / Дериализация древовидной структуры - PullRequest
5 голосов
/ 10 апреля 2009

Я пытаюсь найти лучший способ сохранить (сериализовать), а затем открыть (десериализовать) древовидную структуру. Моя структура состоит из различных типов объектов с разными свойствами, но каждый наследует от базового абстрактного класса "Узел".

Каждый узел имеет уникальный идентификатор (GUID) и метод AddSuperNode (Node nd), который устанавливает родителя узла. Это, в свою очередь, вызывает другие методы, которые позволяют родительскому узлу знать, какие у него есть подузлы. Однако некоторые узлы также используют метод AddAuxSuperNode () , который добавляет вторичного родителя к узлу.

Я использовал двоичную сериализацию, но теперь я думаю, что хочу использовать что-то, где у меня есть немного больше контроля, и сериализованные данные более доступны. Я также хочу сохранить информацию о типе при десериализации и иметь возможность сериализации частных значений. Так что DataContractSerializer показался мне лучшим способом.

Я не могу просто сериализовать корень Узел напрямую из-за узлов, имеющих несколько родителей. Я не хочу создавать дубликаты объектов. Казалось бы, мне нужно деконструировать дерево в плоский список, а затем сериализовать его. Затем после сериализации этого списка восстановить дерево. Это звучит правильно?

Как я уже говорил, каждый Узел имеет уникальный идентификатор GUID, но сейчас Узлы напрямую ссылаются на своих родителей / детей и не хранят свои идентификаторы. Я мог бы обновить методы AddSuperNode () и AddAuxSuperNode () , чтобы также обновить список родительских идентификаторов для сериализации в дополнение к прямым ссылкам. Но я бы предпочел только обновлять / создавать этот список, когда объект сериализуется. Поэтому я подумал создать метод UpdateSuperNodeIDRefs () в узле, который будет вызываться непосредственно перед сериализацией.

Вот что я планирую сделать для сериализации и десериализации этой структуры. Кто-нибудь может предложить лучший / чище / более эффективный способ сделать это?

Сериализация

1) Укажите корневой узел древовидной структуры

2) Разбить древовидную структуру на плоскую Словарь (идентификатор Guid, узел nd) , где id - это guid из и .

3) Вызов UpdateSuperNodeIDRefs () ; для каждого узла обновить идентификаторы, которые он сохранил для своих родителей.

4) Сериализация словаря узлов с DataContractSerializer

Десериализация

1) Десериализовать Словарь узлов

2) Проходите через каждый Узел в Словаре , повторно соединяя каждого с их родителями. Для любых сохраненных идентификаторов родителей найдите соответствующие Узел в Словаре 1068 * с соответствующими идентификаторами. Вызовите AddSuperNode () или AddAuxSuperNode ( ) для повторного подключения узла к его родителю (ям)

3) Из любого узла в словаре найдите корень структуры

4) Вернуть рут Узел

1 Ответ

10 голосов
/ 10 апреля 2009

Если у узла несколько родителей, то это не дерево; по-видимому, это график . Однако - не беспокойтесь; DataContractSerializer может справиться с этим для вас:

using System;
using System.IO;
using System.Runtime.Serialization;

[DataContract]
class Node {
    [DataMember]
    public Node AnotherNode { get; set; }
}

static class Program
{
    static void Main()
    {
        Node a = new Node(), b = new Node();
        // make it a cyclic graph, to prove reference-mode
        a.AnotherNode = b;
        b.AnotherNode = a;

        // the preserveObjectReferences argument is the interesting one here...
        DataContractSerializer dcs = new DataContractSerializer(
            typeof(Node), null, int.MaxValue, false, true, null);
        using (MemoryStream ms = new MemoryStream())
        {
            dcs.WriteObject(ms, a);
            ms.Position = 0;
            Node c = (Node) dcs.ReadObject(ms);
            // so .AnotherNode.Another node should be back to "c"
            Console.WriteLine(ReferenceEquals(c, c.AnotherNode.AnotherNode));
        }

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...