考虑这些类定义:
[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
?
答案 0 :(得分:2)
通过添加[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; }
}
(虽然我不知道为什么)
答案 1 :(得分:1)
因为您要发送Class1的实例,而不是Class2。 如果使用Class1实例调用方法,则无法将其转换为Class2。
您可以创建Class2的新实例,并由Class1实例中的成员填充。 但它看起来很糟糕。