Reputation: 11101
How can I configure the protobuf-net typemodel to pass the 3 unit tests in the example below? Protobuf version is v2 r470.
I have looked at the list tests in the svn tree briefly but can't spot the difference between this and the null vs empty tests in protobuf-net svn.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using ProtoBuf;
using ProtoBuf.Meta;
namespace ProtoCollections
{
[TestFixture]
public class CollectionTests
{
[Test]
public void TestEmptyList()
{
var model = TypeModel.Create();
var orig = new TypeWithReferenceList(Enumerable.Empty<SomeReferenceType>());
var clone = (TypeWithReferenceList)model.DeepClone(orig);
Assert.IsNotNull(clone.List);
Assert.IsEmpty(clone.List);
}
[Test]
public void TestNullList()
{
var model = TypeModel.Create();
var orig = new TypeWithReferenceList(null);
var clone = (TypeWithReferenceList)model.DeepClone(orig);
Assert.IsNull(clone.List);
}
[Test]
public void TestList()
{
var model = TypeModel.Create();
model[typeof (SomeReferenceType)].AsReferenceDefault = true;
SomeReferenceType repeatedItem = new SomeReferenceType(123);
var orig = new TypeWithReferenceList(new []{repeatedItem, repeatedItem});
var clone = (TypeWithReferenceList)model.DeepClone(orig);
Assert.AreEqual(orig.List.Count, clone.List.Count);
Assert.AreSame(orig.List[0], orig.List[1]);
Assert.AreEqual(orig.List[0].Value, clone.List[0].Value);
Assert.AreSame(clone.List[0], clone.List[1]);
}
}
[ProtoContract(ImplicitFields = ImplicitFields.AllFields, SkipConstructor = true)]
public class SomeReferenceType
{
private int value;
public SomeReferenceType(int val)
{
value = val;
}
public int Value { get { return value; } }
}
[ProtoContract(ImplicitFields = ImplicitFields.AllFields, SkipConstructor = true)]
public class TypeWithReferenceList
{
private List<SomeReferenceType> innerList;
public TypeWithReferenceList(IEnumerable<SomeReferenceType> items)
{
innerList = items == null ? null : items.ToList();
}
public List<SomeReferenceType> List { get { return innerList; } }
}
}
Upvotes: 1
Views: 602
Reputation: 1062502
The third appears to be a glitch applying AsReferenceDefault
to implicit fields; it looks like decorating the member manually (with AsReference=true
) works, as does applying it at runtime:
model[typeof(TypeWithReferenceList)][1].AsReference = true;
I will investigate why this is.
The second already passes due to the way protobuf skips over nulls by default.
The first is trickier - again, since the google spec has no concept of null, this is ... problematic. It can currently be spoofed with an annoying couple of fake properties, but not ideal. Personally, I would say "keep it simple; make the collections always non null" (usually via either a field initializer or a deserialization callback). It is also possible that a recent change to allow nulls inside lists can be extended to support explicit nulls outside lists (on an opt-in basis).
The problem here, however, seems to be that you want it to behave like BinaryFormatter
. However, it isn't BinaryFormatter
. It is not designed as a drop-in replacement for BinaryFormatter
(although it can do a good job replacing XmlSerializer
or DataContractSerializer
, which have more similar semantics). The underlying wire-format ultimately has limitations - this being the manifestation of a wire format designed by Google to be efficient and fairly baggage-free.
In particular, most of these "limitations" won't appear when dealing with most DTO models and target scenarios.
Upvotes: 1