正如@Marc 所说,有线格式仅发送项目的数据,因此为了知道列表是空还是空,您必须将该位信息添加到流中。
添加额外的属性来指示原始集合是否为空很容易,但是如果您不想修改原始类型定义,则还有另外两个选择:
使用代理进行序列化
代理类型将具有额外的属性(保持原始类型不变)并将恢复列表的原始状态:null,有项目或为空。
[TestMethod]
public void SerializeEmptyCollectionUsingSurrogate_RemainEmpty()
{
var instance = new SomeType { Items = new List<int>() };
// set the surrogate
RuntimeTypeModel.Default.Add(typeof(SomeType), true).SetSurrogate(typeof(SomeTypeSurrogate));
// serialize-deserialize using cloning
var clone = Serializer.DeepClone(instance);
// clone is not null and empty
Assert.IsNotNull(clone.Items);
Assert.AreEqual(0, clone.Items.Count);
}
[ProtoContract]
public class SomeType
{
[ProtoMember(1)]
public List<int> Items { get; set; }
}
[ProtoContract]
public class SomeTypeSurrogate
{
[ProtoMember(1)]
public List<int> Items { get; set; }
[ProtoMember(2)]
public bool ItemsIsEmpty { get; set; }
public static implicit operator SomeTypeSurrogate(SomeType value)
{
return value != null
? new SomeTypeSurrogate { Items = value.Items, ItemsIsEmpty = value.Items != null && value.Items.Count == 0 }
: null;
}
public static implicit operator SomeType(SomeTypeSurrogate value)
{
return value != null
? new SomeType { Items = value.ItemsIsEmpty ? new List<int>() : value.Items }
: null;
}
}
使您的类型可扩展
protobuf-net 建议使用 IExtensible 接口,它允许您扩展类型,以便可以将字段添加到消息中而不会破坏任何内容(在此处阅读更多内容)。为了使用 protobuf-net 扩展,您可以继承Extensible
类或实现IExtensible
接口以避免继承约束。
现在您的类型是“可扩展的”,您可以定义[OnSerializing]
和[OnDeserialized]
添加新指标的方法,这些指标将被序列化到流中,并在使用原始状态重建对象时从流中反序列化。
优点是您不需要将新属性或新类型定义为代理项,缺点是IExtensible
如果您的类型在类型模型中定义了子类型,则不支持。
[TestMethod]
public void SerializeEmptyCollectionInExtensibleType_RemainEmpty()
{
var instance = new Store { Products = new List<string>() };
// serialize-deserialize using cloning
var clone = Serializer.DeepClone(instance);
// clone is not null and empty
Assert.IsNotNull(clone.Products);
Assert.AreEqual(0, clone.Products.Count);
}
[ProtoContract]
public class Store : Extensible
{
[ProtoMember(1)]
public List<string> Products { get; set; }
[OnSerializing]
public void OnDeserializing()
{
var productsListIsEmpty = this.Products != null && this.Products.Count == 0;
Extensible.AppendValue(this, 101, productsListIsEmpty);
}
[OnDeserialized]
public void OnDeserialized()
{
var productsListIsEmpty = Extensible.GetValue<bool>(this, 101);
if (productsListIsEmpty)
this.Products = new List<string>();
}
}