Protobuf-net null /空列表和引用相等

时间:2011-11-21 20:48:52

标签: .net serialization protobuf-net

如何配置protobuf-net typemodel以通过下面示例中的3个单元测试? Protobuf版本是v2 r470。

我已经简要地查看了svn树中的列表测试,但是没有发现它与protobuf-net svn中的null和empty测试之间的区别。

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

}

1 个答案:

答案 0 :(得分:1)

第三个似乎是将AsReferenceDefault应用于隐式字段的故障;看起来手动装饰成员(使用AsReference=true)可以正常工作,就像在运行时应用它一样:

model[typeof(TypeWithReferenceList)][1].AsReference = true;

我会调查为什么会这样。

由于protobuf默认跳过空值的方式,第二个已经过了。

第一个更棘手 - 再次,因为谷歌规范没有null的概念,这是......有问题的。它目前可能被一些令人讨厌的虚假属性欺骗,但并不理想。就个人而言,我会说“保持简单;使集合始终为非null”(通常通过字段初始化程序或反序列化回调)。也可以扩展最近允许 列表中的空值的更改,以支持列表外的显式空值(在选择加入的基础上)。

然而,这里的问题似乎是你希望它的行为类似于BinaryFormatter。但是,不是 BinaryFormatter。它不是作为BinaryFormatter的替代品而设计的(虽然它可以很好地替换XmlSerializerDataContractSerializer,它们具有更多相似的语义)。潜在的线路格式最终会受到限制 - 这是Google设计的有线和高效且无需行李的有线格式的体现。

特别是,在处理大多数DTO模型和目标场景时,大多数这些“限制”都不会出现。