如何序列化循环引用?

时间:2014-08-08 12:59:14

标签: c# serialization

如何序列化相互引用的对象?

public class Item {}

public class Player
{
    Item weapon;
}

这些实例独立存在:我在某个类中有一个List<Item> gameobjects,在另一个类中有一个带有List<Item> tileobjects的tile类。

1 个答案:

答案 0 :(得分:1)

以下是我解决类似问题的方法。然后,您的序列化程序类应该跟踪已经序列化的对象。例如,通过在已经解析的对象列表中添加其ID。如果是第一次,您应该继续序列化对象,否则您只需编写ID。

反序列化时,恢复此ID并检查序列化程序类是否已反序列化该对象。如果是,则恢复实际对象并重新构建引用。否则,反序列化对象并将其ID添加到另一个已反序列化的对象列表中。

例如,您可能有类似以下的类:

public class GraphSerializer 
{
    Dictionary<string, Node> parsedNodes;

    public void MarkNodeAsParsed(Node node)
    {
        parsedNodes.Add(node.Id, node);
    }

    public bool IsNodeParsed(string id)
    {
        return parsedNodes.ContainsKey(id);
    }

    public Node GetNode(string id)
    {
        return parsedNodes[id];
    }

    [...]
}

现在,当序列化你会做这样的事情,在伪代码中:

public void Serialize(GraphSerializer serializer, ...)
{
    serializer.Write(node.Id);

    bool isNewNode = !serializer.IsNodeParsed(node.Id);
    if (isNewNode) 
    {
        // Write rest of data
        serializer.Write(node);
        serializer.MarkNodeAsParsed(node);
    }

    // Since this node has already been serialized, we don't need  
    // to serialize any other value as we have already written the node Id
}

然后,在反序列化时:

public void Deserialize(GraphSerializer serializer, ...)
{
    string id = serializer.ReadString();
    Node node;

    bool isNewNode = !serializer.IsNodeParsed(node.Id);
    if (isNewNode) 
    {
        // Read rest of data
        node = serializer.Read();
        serializer.MarkNodeAsParsed(node);
    }
    else
    {
        // Node has already been deserialized, so we can just recover it
        node = serializer.GetNode(id);
    }
}