protobuf-net中的对象继承

本文关键字:继承 对象 protobuf-net | 更新日期: 2023-09-27 18:14:24

考虑这些类定义:

[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中适合它?

protobuf-net中的对象继承

通过添加[ProtoInclude(...)],您告诉protobuf-net以允许继承工作的方式处理Class1Class2。无论您指定<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; }
}

(虽然我不知道为什么)

因为您发送的是Class1实例,而不是Class2实例。如果你用Class1的实例调用方法,你不能把它神奇地转换成Class2。

您可以创建Class2的新实例,并由Class1实例中的成员填充。