0

好的,我之前在 SO 上问过一些关于序列化的问题,但我仍然卡住了 - 所以我想我会吐出我的整个案例而不是子问题,希望有人能指出我的鼻子正确的方向:)

我的应用程序类似于 Apple 的“Quartz Composer”,这意味着我有一个连接节点的树状结构。

节点由 INode 接口定义;实际的节点类型/类是使用 MEF 从 DLL 导入的,因此在编译时将不知道节点类型。

节点是连接的,因此双向链接可以并且将会发生。

我想将我的“组合”(整个节点树)保存到一个文件中,最好是像 XML 一样可读。我真的很想避免保存为专有格式!

所以我需要序列化的是:

  • 一棵对象树,其类可以在运行时导入(因此事先不知道),它可以包含双向链接。

  • 最重要的是,我想存储使用的节点类的版本信息,因此可以判断是否使用某个节点类的旧版本存储了“组合”,而不是当前应用程序中使用的 dll / 节点类。

以前我被指向 DataContractSerializer,它似乎是一个很好的工具来存储我的树并完全支持双向链接。

但是,如果我想序列化我的树(接口 IComposition),它会开始抱怨未知类型 - 我必须指定它在序列化树时可能遇到的每种特定类型......

而且我也无法指定用于特定节点类的程序集版本。

不知何故,首先枚举我的整个树以找出已使用哪些节点类,将它们添加到已知类型列表,然后序列化是不对的。

即便如此,我也必须找到一种方法在输出数据中添加一个部分,以指定使用的类的版本信息。

也许我是唯一一个遇到这个问题的人,但我真的希望其他人以前遇到过并克服过这个问题——最好是用一个优雅的解决方案;)我可以想象这不是标准 .NET 序列化程序可以处理的事情,但是也许有一些第 3 方(免费,甚至开源?)实施?

4

1 回答 1

0

您可以使用BinaryFormatterSoapFormatter完成此操作。这些格式化程序与任意对象图一起工作,并将处理它们遇到的任何对象(只要对象的类型被标记[Serializable]),并将正确地保留循环引用。如果您想了解对象是如何序列化的,请使用 SoapFormatter,它将输出 XML。

请注意,任何可以按需加载的程序集都必须在 GAC 中,否则运行时将找不到它们。

要处理版本控制,您可以执行以下操作:

[Serializable]
public class SomeVersionedClass : IDeserializationCallback
{
    private const int CURRENT_VERSION = 10;

    private int version = CURRENT_VERSION;

    void IDeserializationCallback.OnDeserialization(object sender)
    {
        if (version != CURRENT_VERSION)
            throw new ApplicationException(
                "Mismatch between serialized data version " + version +
                " and required version " + CURRENT_VERSION + ".");
    }
}

请注意,您可能会考虑将数据从以前的版本布局迁移到新版本,而不是引发异常。此外,请注意从类中删除序列化字段将完全阻止将来的反序列化,因此如果您计划允许从不再使用的字段迁移,则必须保留该字段,以便以前的版本可以正确反序列化(当然,这样您就可以获取数据来迁移它)。

于 2010-12-27T21:26:35.740 回答