protobuf-net并使用接口序列化链表

时间:2012-09-27 14:00:21

标签: serialization interface protobuf-net

我遇到过protobuf-net的问题,并将其缩小到最简单的情况。 我想要一个链表类型结构,其中一个类具有相同类型的属性。当我序列化它时,效果很好。但是,如果类型是接口而不是类,我会收到以下错误: 为ConsoleApplication1.foo(ConsoleApplication1.ifoo)生成序列化程序后,无法更改该类型

这是我必须生成此错误的代码:

class Program
{
    static void Main(string[] args)
    {
        var toSerialize = new foo();
        toSerialize.data = "foo1";

        var subf = new foo();
        subf.data = "foo2";

        toSerialize.subfoo = subf;

        using (var pbfsc = new FileStream("testfile.proto", FileMode.Create))
        {
            using (var cs = new GZipStream(pbfsc, CompressionMode.Compress))
            {
                ProtoBuf.Serializer.Serialize(cs, toSerialize);
            }
            pbfsc.Close();
        }
    }
}

[ProtoContract, ProtoInclude(2000, typeof(foo))]
public interface ifoo
{
    [ProtoMember(1)]
    string data { get; set; }
    [ProtoMember(2)]
    ifoo subfoo { get; set; }
}
[ProtoContract]
public class foo : ifoo
{

    [ProtoMember(1)]
    public string data { get; set; }
    [ProtoMember(2)]
    public ifoo subfoo { get; set; }
}

我已经完成了关于这个主题的所有阅读,我无法看到我做错了什么。我尝试将我的对象放在一个包装类中,因为它看起来类似于接口列表的问题(代码未显示),但这仍然无济于事。

如果我将subfoo更改为foo,那么它工作正常,但在我更复杂的现实问题中,我宁愿坚持使用界面。我在这里做错了什么,或者这是protobuf-net的问题吗?

非常感谢任何帮助。

干杯

亚历

1 个答案:

答案 0 :(得分:1)

在实现作为合同的接口时,有一些未完成的工作需要完成以改进顶级对象的处理。基本上,目前它只处理根对象的非接口部分,但处理属性/子对象等的接口。

你看到的例外是略微奇怪 - 由于ifoo属性,我希望它及时知道subfoo,但这里的根本问题可以通过添加:

来避免
Serializer.PrepareSerializer<ifoo>();

在序列化代码之前(理想情况是很早的某个地方;你只需要调用一次)。

但是,我还应该注意到你实际上在这里进行了双序列化:序列化ifoo subfoo属性时,它将从接口接口({{1具体类型(ifoo。这些实际上是相同的值,因此这里有一些冗余。

说:从具体类型中取出成员级属性,但是根对象故障会使这个问题稍微有些问题。解决两个问题(不再需要foo)的另一个修复是:

PrepareSerializer

当解决了根对象/接口支持故障时,不需要using ProtoBuf; using System; class Program { static void Main(string[] args) { var root = new foo(); root.data = "foo1"; var subf = new foo(); subf.data = "foo2"; root.subfoo = subf; var toSerialize = new FooRoot { root = root }; // this does the same as your file-code, but runs // both serialize and deserialize - basicaly, it is // a lazy way of checking it end-to-end var clone = Serializer.DeepClone(toSerialize).root; Console.WriteLine(clone.data); // "foo1" Console.WriteLine(clone.subfoo.data); // "foo2" } } [ProtoContract] public class FooRoot { [ProtoMember(1)] public ifoo root { get; set; } } [ProtoContract, ProtoInclude(2000, typeof(foo))] public interface ifoo { [ProtoMember(1)] string data { get; set; } [ProtoMember(2)] ifoo subfoo { get; set; } } [ProtoContract] public class foo : ifoo { public string data { get; set; } public ifoo subfoo { get; set; } } 包装器,但我可能需要添加一些开关来启用/禁用修复,以用于传统支持。 / p>