protobuf-net中的对象继承

时间:2014-07-23 08:45:58

标签: c# protobuf-net

考虑这些类定义:

[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

2 个答案:

答案 0 :(得分:2)

通过添加[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; }
}

(虽然我不知道为什么

答案 1 :(得分:1)

因为您要发送Class1的实例,而不是Class2。 如果使用Class1实例调用方法,则无法将其转换为Class2。

您可以创建Class2的新实例,并由Class1实例中的成员填充。 但它看起来很糟糕。