I've run in to a problem with protobuf-net and I hope it is user error and not a bug with protobuf-net.
I can serialize an empty collection (for example, IDictionary<string, string>()
) and then deserialize the collection. The deserialization results in a non-null object (exactly as I serialized).
However, things get wonky if the collection belongs to another type. Serializing the custom type with a non-null empty collection results in a deserialization where the collection is null.
Below is an example of what I am working on and unit tests that illustrate the problem.
The test Test_Protobuf_EmptyDictionary_SerializeDeserialize
passes.
The test Test_Protobuf_EmptyCollectionAndPopulatedCollection_SerializeDeserialize
fails.
[ProtoContract]
[ProtoInclude(100, typeof(ConcreteA))]
public abstract class AbstractClass
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public IDictionary<string, string> FieldsA { get; set; }
[ProtoMember(3)]
public IDictionary<string, string> FieldsB { get; set; }
[ProtoMember(4)]
public ICollection<string> FieldsC { get; set; }
[ProtoMember(5)]
public ICollection<string> FieldsD { get; set; }
}
[ProtoContract]
[ProtoInclude(110, typeof(ConcreteB))]
public class ConcreteA : AbstractClass
{
public ConcreteA() {}
}
[ProtoContract]
[ProtoInclude(120, typeof(ConcreteC))]
public class ConcreteB : ConcreteA
{
[ProtoMember(1)]
public int Age { get; set; }
public ConcreteB() {}
}
[ProtoContract]
public class ConcreteC : ConcreteB
{
[ProtoMember(1)]
public string HairColor { get; set; }
}
[TestFixture]
public class ProtobufTests
{
[Test]
public void Test_Protobuf_EmptyDictionary_SerializeDeserialize()
{
IDictionary<string,string> dictionary = new Dictionary<string, string>();
ICollection<string> collection = new List<string>();
Assert.IsNotNull(dictionary);
Assert.IsNotNull(collection);
Assert.AreEqual(0, dictionary.Keys.Count);
Assert.AreEqual(0, collection.Count);
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, dictionary);
ms.Position = 0;
var deserialized = Serializer.Deserialize<IDictionary<string, string>>(ms);
Assert.IsNotNull(deserialized);
Assert.AreEqual(0, deserialized.Keys.Count);
}
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, collection);
ms.Position = 0;
var deserialized = Serializer.Deserialize<ICollection<string>>(ms);
Assert.IsNotNull(deserialized);
Assert.AreEqual(0, deserialized.Count);
}
}
[Test]
public void Test_Protobuf_EmptyCollectionAndPopulatedCollection_SerializeDeserialize()
{
ConcreteC c = new ConcreteC {
FieldsA = new Dictionary<string, string>(),
FieldsB = new Dictionary<string, string> {{"john", "elway"}},
FieldsC = new List<string>(),
FieldsD = new List<string>{"james", "jones"}
};
Assert.IsNotNull(c);
Assert.IsNotNull(c.FieldsA);
Assert.IsNotNull(c.FieldsB);
Assert.IsNotNull(c.FieldsC);
Assert.IsNotNull(c.FieldsD);
Assert.AreEqual(0, c.FieldsA.Keys.Count);
Assert.AreEqual(1, c.FieldsB.Keys.Count);
Assert.AreEqual(0, c.FieldsC.Count);
Assert.AreEqual(2, c.FieldsD.Count);
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, c);
ms.Position = 0;
var deserialized = Serializer.Deserialize<ConcreteC>(ms);
Assert.IsNotNull(deserialized);
Assert.IsNotNull(deserialized.FieldsA); // first failing test
Assert.IsNotNull(deserialized.FieldsB);
Assert.IsNotNull(deserialized.FieldsC);
Assert.IsNotNull(deserialized.FieldsD);
Assert.AreEqual(0, deserialized.FieldsA.Keys.Count);
Assert.AreEqual(1, deserialized.FieldsB.Keys.Count);
Assert.AreEqual(0, deserialized.FieldsC.Count);
Assert.AreEqual(1, deserialized.FieldsD.Count);
}
}
}