序列化自定义集合的异常

时间:2012-07-23 14:50:53

标签: protobuf-net

感谢伟大的图书馆Marc和SO的所有答案。

我正在使用来自http://code.google.com/p/protobuf-net/downloads/list的.NET 4.0.zip上的protobuf-net r480.zip。这是最新的稳定版本吗?

我在序列化自定义集合时遇到问题。

public static void TestSerialization() {
    using (var stream = new MemoryStream()) {
        var b1 = new B1 { 1 };
        // Throws System.ArgumentException: Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be subclassed
        Serializer.Serialize(stream, b1);
    }

    using (var stream = new MemoryStream()) {
        var b2 = new B2 { 2 };
        Serializer.Serialize(stream, b2);
        stream.Position = 0;
        var b2Deserialized = Serializer.Deserialize<B2>(stream);

        // This fails because b2Deserialized.Count is 0.
        Assert.AreEqual(1, b2Deserialized.Count);
    }

    using (var stream = new MemoryStream()) {
        RuntimeTypeModel.Default[typeof(A2<int>)].AddSubType(1000, typeof(B2));
        var b2 = new B2 { 2 };
        // Throws System.ArgumentException: Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be subclassed
        Serializer.Serialize(stream, b2);
    }
}

[ProtoContract]
[ProtoInclude(1000, typeof(B1))]
public class A1<T> : List<T> { }

[ProtoContract]
public class B1 : A1<int> { }

[ProtoContract]
public class A2<T> : List<T> { }

[ProtoContract]
public class B2 : A2<int> { }

感谢anser Marc,如果只使用列表,删除Proto属性会很有效。不幸的是,实际代码更复杂 - 派生集合包含其他值(在实际代码中,实体类型中的模板参数而不是int,集合中的成员是对集合中元素的父级的引用)。这是一个更好的代表。

    public static void TestSerialization() {
        using (var stream = new MemoryStream()) {
            var b = new B { 23 };
            b.SomeValue = "abc";
            Serializer.Serialize(stream, b);

            stream.Position = 0;
            var deserialized = Serializer.Deserialize<B>(stream);
            Assert.AreEqual(1, deserialized.Count);
            Assert.AreEqual(b[0], deserialized[0]);

            // This fails because deserialized.SomeValue == null
            Assert.AreEqual(b.SomeValue, deserialized.SomeValue);
        }
    }

    public class A<T> : List<T> { }

    public class B : A<int>
    {
        [ProtoMember(1)]
        public string SomeValue;
    }

1 个答案:

答案 0 :(得分:1)

IMO错误消息非常清楚:列表不支持继承。这是因为列表没有占位符,因此无处存储此信息。在XML术语中(注意protobuf与XML不同),它就像输出(如果你熟悉XmlSerializer):

[XmlElement("item")]
public List<Foo> Items { get; set; }

仅输出:

<item>...</item>
<item>...</item>
<item>...</item>

(但没有“项目”节点 - 你无法对列表本身说什么)

我试图理解你试图用继承代表什么。坦率地说,我没有看到任何有用的东西 - 因为列表具有内置行为,您不需要为这些定义合同;只需将它们用作列表。

一般来说,封装列表通常更好,而不是继承