问题
Thanks for the great library Marc and for all the answers on SO.
I'm using protobuf-net r480.zip on .NET 4.0.zip from http://code.google.com/p/protobuf-net/downloads/list. Is this the latest stable release?
I'm having trouble serializing a custom collection.
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> { }
Thanks for the anser Marc, removing the Proto attributes works great if just using a list. Unfortunately, the actual code is more complex - the derived collection contains other values (in the real code the template parameter in of type Entity instead of int and the member in the collection is a reference to the parent of the elements in the collection). Here is a better representation.
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 the error message is quite clear: inheritance is not supported on lists. This is because lists don't have a place-holder, so there is nowhere to store this information. In XML terms (noting that protobuf is nothing like XML), it is like the output of (if you are familiar with XmlSerializer):
[XmlElement("item")]
public List<Foo> Items { get; set; }
Which outputs just:
<item>...</item>
<item>...</item>
<item>...</item>
(but no "Items" node - there exists nowhere that you could say anything about the list itself)
I'm trying to understand what you are trying to represent with that inheritance. Frankly, I'm not seeing anything useful - since lists have inbuilt behaviour, you don't need to define contracts for these at all; just use them as lists.
In the general sense, it is usually better to encapsulate lists, not inherit them.
来源:https://stackoverflow.com/questions/11614968/exception-serializing-custom-collection