我已经阅读了各种与继承有关的帖子,并且Protocol Buffers不支持继承.我不想在Protocol Buffers消息中继承,而是继承,所以我可以轻松处理所有的Protocol Buffers消息. 我使用protobuf-net 2.0.0.480和.p
我使用protobuf-net 2.0.0.480和.proto文件来定义我的协议.这一切都运行良好,除非我到了一个共同的祖先,以便我可以做一些共同的功能,并允许轻松检查.一个简单的例子:
我的.proto文件:
message ProtocolInformation { enum MessageKinds { LAYOUT_ADVANCE = 1; LAYOUT_RENDER = 2; } required MessageKinds MessageKind = 1; required int32 UniqueID = 2; } message GFX_Layout_Advance { required ProtocolInformation ProtocolInfo = 1; required int32 LayoutHandle = 2; } message GFX_Layout_Render { required ProtocolInformation ProtocolInfo = 1; required int32 LayoutHandle = 2; required int32 Stage = 3; }
最终为GFX_Layout_Advance生成类,GFX_Layout_Render为(只有GFX_Layout_Advance的一部分)显示:
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name = @"GFX_Layout_Advance")] public partial class GFX_Layout_Advance : global::ProtoBuf.IExtensible { public GFX_Layout_Advance() { } private GFX_Protocol.ProtocolInformation _ProtocolInfo; [global::ProtoBuf.ProtoMember(1, IsRequired = true, Name = @"ProtocolInfo", DataFormat = global::ProtoBuf.DataFormat.Default)] public GFX_Protocol.ProtocolInformation ProtocolInfo
因为它是一个部分类,似乎没有我实现的可重写构造函数:
public partial class GFX_Layout_Advance : GfxProtocolMessageBase { public override ProtocolInformation ProtocolInformation() { return ProtocolInfo; } }
这将允许我将所有传入的消息视为GfxProtocolMessageBase并允许查询ProtocolInformation,以便我可以转换为适当的后代.在这种情况下GFX_Layout_Advance.然而…..
>添加其他部分类GFX_Layout_Advance()会导致不同的protobuf编码.由于接口的唯一变化是一种方法,我不明白为什么会这样?
底线是:
>我想为所有生成的protobuf-net类引入一个共同的基础祖先
>基本祖先类将允许我访问有关我正在处理什么类型的消息的信息,因为我不想在我准备好之前必须转换为实际的消息类型
我如何实现1.& 2.?
所有指针都赞赏.
>是的,只要GfxProtocolMessageBase不是契约类型就可以正常工作.它故意使用部分类来允许这种类型的东西.编码数据不应该改变.如果你有一个我可以看到的行为不端的情景,我会很乐意调查.>那没关系;只是:不要使用Serializer.Serialize< GfxProtocolMessageBase> / Serializer.Deserialize< GfxProtocolMessageBase>,因为序列化程序不应该知道GfxProtocolMessageBase(除非你很高兴,但这确实意味着你不会遵循现有的.proto 100%).对于序列化,Serializer.NonGeneric.Serialize或typeModel.Serialize(例如,RuntimeTypeModel.Default.Serialize)将自动执行正确的操作.对于反序列化,您需要知道实际的目标类型.
当然,替代选项是允许GfxProtocolMessageBase被序列化程序称为基类型,并使用protobuf-net的内置继承支持([ProtoInclude(…)]等) – 但问题是:赢了将100%映射到.proto,因为继承是作为封装实现的(通过protobuf-net),这意味着:它将被编写为具有许多可选子消息字段的基本消息.
编辑以显示从单个流中读取不同对象(异构类型)的类型解析器用法:
using ProtoBuf; using System; using System.Collections.Generic; using System.IO; [ProtoContract] class Foo { [ProtoMember(1)] public int Id { get; set; } public override string ToString() { return "Foo with Id=" + Id; } } [ProtoContract] class Bar { [ProtoMember(2)] public string Name { get; set; } public override string ToString() { return "Bar with Name=" + Name; } } static class Program { // mechanism to obtain a Type from a numeric key static readonly Dictionary<int, Type> typeMap = new Dictionary<int, Type> { {1,typeof(Foo)}, {2,typeof(Bar)} }; static Type ResolveType(int key) { Type type; typeMap.TryGetValue(key, out type); return type; } static void Main() { // using MemoryStream purely for convenience using (var ms = new MemoryStream()) { // serialize some random data (here I'm coding the outbound key // directly, but this could be automated) Serializer.SerializeWithLengthPrefix(ms, new Foo { Id = 123 }, PrefixStyle.Base128, 1); Serializer.SerializeWithLengthPrefix(ms, new Bar { Name = "abc" }, PrefixStyle.Base128, 2); Serializer.SerializeWithLengthPrefix(ms, new Foo { Id = 456 }, PrefixStyle.Base128, 1); Serializer.SerializeWithLengthPrefix(ms, new Bar { Name = "def" }, PrefixStyle.Base128, 2); // rewind (this wouldn't be necessary for a NetworkStream, // FileStream, etc) ms.Position = 0; // walk forwards through the top-level data object obj; while (Serializer.NonGeneric.TryDeserializeWithLengthPrefix( ms, PrefixStyle.Base128, ResolveType, out obj)) { // note we overrode the ToString on each object to make // this bit work Console.WriteLine(obj); } } } }