定义了protobuf-net序列化所需的proto2消息类型?
Posted
技术标签:
【中文标题】定义了protobuf-net序列化所需的proto2消息类型?【英文标题】:defined proto2 message-type necessary for protobuf-net serialization? 【发布时间】:2016-09-27 03:44:59 【问题描述】:protobuf-net v2.1.0 ( latest available as NuGet package )
Visual Studio 2015 v14
C#
我没有使用 protogen.exe
从消息类型定义生成我的类
因为我有额外的要求,所以我编写了自己的生成器,它编写了以下类:
[Serializable]
public partial class MyType: ProtoBuf.IExtensible
[ProtoBuf.ProtoMember(1, IsRequired = false, Name = @"RegistrationDate", DataFormat = ProtoBuf.DataFormat.Default)]
[System.ComponentModel.DefaultValue("1/1/0001 12:00:00 AM")]
public DateTime RegistrationDate;
[ProtoBuf.ProtoMember(2, IsRequired = false, Name = @"RegistrationId", DataFormat = ProtoBuf.DataFormat.TwosComplement)]
[System.ComponentModel.DefaultValue(null)]
public long? RegistrationId;
但是当我尝试序列化时:
var myObject = new MyType(RegistrationDate="2016-01-01",RegistrationId=1);
var stream = new MemoryStream();
ProtoBuf.Serializer.Serialize(stream, myObject );
protobuf-net
抛出异常:
“System.InvalidOperationException”类型的异常发生在 protobuf-net.dll 但未在用户代码中处理
附加信息:类型不是预期的,没有合同可以 推断:MyNamespace.MyType
显然protobuf-net
期望类声明用原型合同属性装饰:
[Serializable]
[ProtoBuf.ProtoContract(Name=@"MyTypeProto")]
public partial class MyType: ProtoBuf.IExtensible
但是,由于我使用诸如 DateTime
和 int?
之类的类型,我不相信我可以创建兼容的 proto2
消息类型。
如何构造我的类以便protobuf-net
可以成功序列化?
更新:如果我添加 [Protobuf.ProtoContract]
属性,那么我可以序列化/反序列化而不会引发异常,但我的反序列化对象丢失了所有值(所有字段均为 null):
[Serializable]
[Protobuf.ProtoContract]
public partial class MyType: ProtoBuf.IExtensible
[ProtoBuf.ProtoMember(1, IsRequired = false, Name = @"RegistrationDate", DataFormat = ProtoBuf.DataFormat.Default)]
[System.ComponentModel.DefaultValue("1/1/0001 12:00:00 AM")]
public DateTime RegistrationDate;
[ProtoBuf.ProtoMember(2, IsRequired = false, Name = @"RegistrationId", DataFormat = ProtoBuf.DataFormat.TwosComplement)]
[System.ComponentModel.DefaultValue(null)]
public long? RegistrationId;
var myObject = new MyType(RegistrationDate="2016-01-01",RegistrationId=1);
var stream = new MemoryStream();
ProtoBuf.Serializer.Serialize(stream, myObject );
var deserialized = ProtoBuf.Serializer.Deserialize<MyType>(stream);
// deserialized.RegistrationDate is null
// deserialized.RegistrationId is null
【问题讨论】:
【参考方案1】:它所要求的只是告诉它你的类型确实是用于 protobuf 序列化的;所以:
[ProtoBuf.ProtoContract]
public partial class MyType ...
名称完全是可选的。事实上,protobuf-net 的大多数 使用是代码优先而不是模式优先(甚至是模式优先),所以我敢打赌,不寻常明确的名称。
不过,作为旁注; DateTime
和 int?
都可以用 .proto
表示(尽管 int?
比 DateTime
干净得多 - 它只是变成了一个 optional
字段,如果你选择从类型模型生成模式,您不需要)。
它不承认[Serializable]
,因为这意味着完全不同的东西,甚至不是在所有平台上都可用。
【讨论】:
谢谢马克。但是 DateTime 和 int 怎么可能呢?允许在 proto2 中使用吗?我认为 proto3 Timestamp 和 IntValue 类型是专门为了弥补 proto2 的这些不足而引入的。 @BaltoStar 我没有说它使用了 proto 3 的Timestamp
;) 而 optional int
在 proto2 中很好;问题是 proto3 从语法中删除了“可选”(但:不会改变线路格式)
好吧,这是我的最新理解:对于纯 .NET 实现(线路两侧的 .NET)protobuf-net 不需要消息类型的合同——至少不像 .proto 中明确表达的那样文件。实际上,此类合约可能会不必要地增加复杂性并引起混淆(例如,当需要原始版本不支持的类型时)。最好让语言对象模型隐式表达合同。正确吗?
如果为了更好地记录我的合同,我确实想创建包含 DateTime 类型的 proto2 消息类型——那么为了使 protogen.exe 正常工作,我需要包含 bcl.proto ,正确?
@BaltoStar yar,DateTime
真的是为 .net-.net 设计的;如果你想要更好的外部支持,我会推荐一个ulong
shim (例如)unix 时间以上是关于定义了protobuf-net序列化所需的proto2消息类型?的主要内容,如果未能解决你的问题,请参考以下文章
名为“名称”的操作不符合所需的签名。参数类型必须是实体类型或预定义的可序列化类型之一
protobuf-net 中没有为 System.Version 定义序列化程序
使用自定义十进制原型合约(C#/C++ 互操作)时,Protobuf-net(反)序列化小数抛出