Сериализация / дериализация древовидной структуры

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

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

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

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

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

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

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

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

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

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

4) Сериализуйте Словарь узлов с помощью DataContractSerializer.

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

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

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

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

4) Верните корневой узел


person Eric Anastas    schedule 10.04.2009    source источник


Ответы (1)


Если у узла несколько родителей, то это не дерево; предположительно это график. Однако - не волнуйтесь; 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));
        }

    }
}
person Marc Gravell    schedule 10.04.2009