protobuf-net 中的对象继承
Posted
技术标签:
【中文标题】protobuf-net 中的对象继承【英文标题】:Object inheritance in protobuf-net 【发布时间】:2014-07-23 08:45:58 【问题描述】:考虑这些类定义:
[ProtoContract, ProtoInclude(2, typeof(Class2))]
class Class1
[ProtoMember(1)]
public string Field1 get; set;
[ProtoContract]
class Class2 : Class1
[ProtoMember(1)]
public string Field2 get; set;
我正在努力实现以下目标:
using (var ms = new MemoryStream())
var c1 = new Class1 Field1 = "hello" ;
Serializer.Serialize<Class1>(ms, c1);
ms.Position = 0;
var c2 = Serializer.Deserialize<Class2>(ms);
但我得到以下异常:Unable to cast object of type 'ProtoBufTest.Class1' to type 'ProtoBufTest.Class2'
我真的不明白这个问题;我的理解是,在反序列化时,Protobuf 应该只将传入的流视为字节的集合,那么为什么它显然首先反序列化为 Class1
对象,然后尝试将其放入 Class2
中?
【问题讨论】:
【参考方案1】:通过添加[ProtoInclude(...)]
,您告诉protobuf-net 以允许继承工作的方式处理Class1
和Class2
。无论您指定<Class1>
还是<Class2>
,protobuf-net 都将从基础类型开始向上构建;基本上你的模型已经变成了(在 protobuf 中):
message Class1
optional string Field1 = 1;
// the following represent sub-types; at most 1 should have a value
optional Class2 Class2 = 2;
message Class2
optional string Field2 = 1;
如果存在.Class2
实例,它将反序列化为Class2
;否则它将反序列化为Class1
。这是有意,因此如果您序列化Class1
,您将返回一个Class1
,如果您序列化一个Class2
,您将返回一个Class2
。
如果要分别考虑这两种类型,不要添加[ProtoInclude]
。事实上,在这种情况下,您甚至可以使用Serializer.ChangeType
来进行序列化/反序列化往返:
var c1 = new Class1 Field1 = "hello" ;
var c2 = Serializer.ChangeType<Class1, Class2>(c1);
注意:在那种情况下,我想知道为什么首先存在继承关系。从你正在做的事情来看,感觉就像你实际上只是想要:
[ProtoContract]
class Class1
[ProtoMember(1)]
public string Field1 get; set;
[ProtoContract]
class Class2
[ProtoMember(1)]
public string Field2 get; set;
(虽然我不知道为什么)
【讨论】:
感谢您的详尽解释。实际上,我真的不需要 Class2 中的任何 ProtoMember,因为我的用例是反序列化 Class1 并在将其发送到客户端之前使用其他字段对其进行扩充(对象中的字段“平面”用于 JSON 序列化)。我试过 Serializer.ChangeType 但结果中 Field1 和 Field2 都为空。 @ThomasWeiss 在这里工作得很好......需要看看它不工作的例子 通过使用我的帖子中没有 ProtoInclude 的类定义,并调用 c2 = Serializer.ChangeType因为您发送的是 Class1 的实例,而不是 Class2。 如果你用 Class1 的实例调用方法,你不能神奇地将它转换为 Class2。
您可以创建 Class2 的新实例并由 Class1 实例中的成员填充。 但它看起来像糟糕的设计。
【讨论】:
调用 Serializer.Deserialize以上是关于protobuf-net 中的对象继承的主要内容,如果未能解决你的问题,请参考以下文章
Protobuf-net 中的继承:ProtoInclude 和兼容性