2012-07-23 50 views
1

感谢伟大的图书馆Marc和SO上的所有答案。异常序列化自定义集合

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

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

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> { } 

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

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

IMO错误信息很清楚:列表上不支持继承。这是因为名单没有占位符,所以无法存储这些信息。在XML方面(注意,protobuf的是没有像XML),很喜欢的输出(如果你熟悉的XmlSerializer):

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

刚刚输出:

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

(但没有“项目“节点 - 没有什么地方可以说关于列表本身的任何东西)

我试图理解你用继承来表示什么。坦率地说,我没有看到任何有用的东西 - 因为列表包含内置行为,所以您无需为这些定义合同,全部为;只是将它们用作列表。

在一般意义上,它通常是更好地封装名单,不继承他们。

+0

感谢您的回答马克。你可能猜到了,但实际的代码更多参与。我已经更新了原来的问题。 – user1546077 2012-07-23 15:36:20

+0

@ user1546077由于protobuf规范,我无法支持列表成员。 ** **(排他)列表,**或**序列化实体。我可以做一些*欺骗*(作为自己的包装),但它需要工作。我会建议:如果你看到不同,我会建议:有属性和*有*列表,而不是*列表*。 – 2012-07-23 16:37:57

+0

了解。我将使用包含列表和额外数据并将其序列化的代理项。 – user1546077 2012-07-23 16:43:47