protobuf网空/空列表和引用相等 [英] Protobuf-net null/empty lists and reference equality
问题描述
我如何配置protobuf网typemodel通过在下面的例子中,3单元测试? protobuf的版本为V2 R470。
我已经看过了SVN树列表测试简单,但不能发现这一点,空VS在protobuf网SVN空测试之间的差异。
使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用NUnit.Framework;
使用protobuf的;
使用ProtoBuf.Meta;
命名空间ProtoCollections
{
[的TestFixture]
公共类CollectionTests
{
[测试]
公共无效TestEmptyList()
{
VAR模型= TypeModel.Create();
VAR原稿=新TypeWithReferenceList(Enumerable.Empty< SomeReferenceType>());
VAR克隆=(TypeWithReferenceList)model.DeepClone(原稿);
Assert.IsNotNull(clone.List);
Assert.IsEmpty(clone.List);
}
[测试]
公共无效TestNullList()
{
VAR模型= TypeModel.Create();
VAR原稿=新TypeWithReferenceList(空);
VAR克隆=(TypeWithReferenceList)model.DeepClone(原稿);
Assert.IsNull(clone.List);
}
[测试]
公共无效TestList()
{
VAR模型= TypeModel.Create();
。模型[typeof运算(SomeReferenceType)AsReferenceDefault = TRUE;
SomeReferenceType repeatedItem =新SomeReferenceType(123);
VAR原稿=新TypeWithReferenceList(新[] {repeatedItem,repeatedItem});
VAR克隆=(TypeWithReferenceList)model.DeepClone(原稿);
Assert.AreEqual(orig.List.Count,clone.List.Count);
Assert.AreSame(orig.List [0],orig.List [1]);
Assert.AreEqual(orig.List [0]。价值,clone.List [0]。价值);
Assert.AreSame(clone.List [0],clone.List [1]);
}
}
[ProtoContract(ImplicitFields = ImplicitFields.AllFields,SkipConstructor =真)
公共类SomeReferenceType
{
私人int值;
公共SomeReferenceType(INT VAL)
{
值= VAL;
}
公众诠释价值{{返回值; }}
}
[ProtoContract(ImplicitFields = ImplicitFields.AllFields,SkipConstructor =真)
公共类TypeWithReferenceList
{
私人列表< SomeReferenceType> innerList;
公共TypeWithReferenceList(IEnumerable的< SomeReferenceType>项目)
{
innerList =项目== NULL?空:items.ToList();
}
公开名单< SomeReferenceType>列表{{返回innerList; }}
}
}
第三个似乎是将毛刺 AsReferenceDefault
来隐场;它看起来像手工装饰件(带 AsReference = TRUE
)的作品一样,在运行时将其应用:
模型[typeof运算(TypeWithReferenceList)] [1] .AsReference =真;
我将调查这是为什么。
第二个已经由于protobuf的默认跳过空值的方式传递。
首先是棘手 - 再次,由于谷歌的规范都是空的概念,这是... ...有问题。它目前可以欺骗与恼人的几个假的性质,但不理想。就个人而言,我会说保持简单,使总的集合非空(通常是通过任何一个领域的初始化或反序列化回调)。这也有可能是最近的更改为允许空值的在的列表可以扩展为支持显式空值的之外的名单(在一个选择的基础上)。
这里的问题,然而,似乎是你希望它表现得像的BinaryFormatter
。然而,它的不是 的BinaryFormatter
。它不是被设计成一个简易替换的BinaryFormatter
(虽然也能做好替换的XmlSerializer
或的DataContractSerializer
,其中有更多类似的语义)。底层钢丝格式最终也有局限性 - 一个传输格式由谷歌设计的这种作为的表现有效率和公平的行李免费
在特定的,大多数这些限制时不会与大多数DTO模式和目标的方案处理出现。
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; } }
}
}
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.
这篇关于protobuf网空/空列表和引用相等的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!