更新时间:2023-02-17 12:55:02
第三个似乎是将毛刺 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.