5

我试图找出保存(序列化)然后打开(反序列化)树结构的最佳方法。我的结构由具有不同属性的各种对象类型组成,但每个对象类型都继承自一个基本的抽象“节点”类。

每个节点都有唯一的 ID (GUID),并有一个 AddSuperNode(Node nd) 方法来设置节点的父节点。这反过来又调用了其他方法,允许父节点知道它有哪些子节点。但是,一些节点也使用AddAuxSuperNode()方法将次父节点添加到节点。

我使用的是二进制序列化,但现在我想我想使用一些我有更多控制权的东西,并且序列化的数据更容易访问。我还想在反序列化时保留类型信息,并能够序列化私有值。所以DataContractSerializer似乎是最好的方法。

我不能直接序列化根节点,因为节点有多个父节点。我不想创建重复的对象。所以看起来我需要将树解构为一个平面列表,然后将其序列化。然后在序列化该列表之后重建树。这听起来对吗?

就像我之前所说的,每个节点都有一个唯一的 GUID 标识符,但是现在节点直接引用它们的父/子,并且不存储它们的 id。除了直接引用之外,我还可以更新AddSuperNode()AddAuxSuperNode()方法来更新要序列化的父 ID 列表。但我宁愿只在对象被序列化时更新/创建这个列表。所以我正在考虑在节点中创建一个UpdateSuperNodeIDRefs()方法,该方法将在序列化之前被调用。

以下是我打算为这个结构的序列化和反序列化做的事情。谁能建议一种更好/更清洁/更有效的方法来做到这一点?

序列化

1)提供树结构的根节点

2) 将树结构分解为一个平面Dictionary(Guid id,Node nd),其中idndguid

3) 调用UpdateSuperNodeIDRefs();为每个节点更新它为其父节点保存的 ID。

4)使用DataContractSerializer序列化节点字典

反序列化

1)反序列化节点字典

2)遍历Dictionary中的每个节点,将每个节点重新连接到它们的父节点。对于存储的任何父 ID ,在字典中找到具有匹配 ID的相应节点,调用AddSuperNode()AddAuxSuperNode()以将节点重新连接到其父节点

3)从字典中的任何节点找到结构的根

4)返回根节点

4

1 回答 1

10

如果一个节点有多个父节点,那么它不是树;大概是一张。但是 - 不要担心;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));
        }

    }
}
于 2009-04-10T07:48:45.747 回答