我开发了一个应用程序,用于使用序列化对象将数据从客户端发送到服务器和返回等。
对于这个应用程序,我认为protobuf-net是一个不错的选择(特别是当它处理可变长度的对象时)。
但是,当从客户端向服务器发送对象或反之亦然时,我所知道的是该对象将是“ReplicableObject”的子类。因此,我正在使用:
Serializer.SerializeWithLengthPrefix(stream, ro, PrefixStyle.Base128);
其中'ro'是从ReplicableObject继承的类型的对象。
但是,我得到了这个例外:
发生了'ProtoBuf.ProtoException'类型的未处理异常 protobuf的-net.dll
其他信息:序列化期间发现意外类型; ProtoIncludeAttribute必须包含类型;找到了MessageObject 作为ReplicableObject传递
在这个特定的例子中,我正在尝试发送 MessageObject 。
由于protobuf-net的文档很少,我不知所措。我在这里尝试了一些属性但无济于事。
任何帮助表示感谢。
编辑:我应该说明子类可能不是我写的那些。
答案 0 :(得分:1)
Protobuf是一种基于合同的序列化格式,旨在与平台无关。因此, no 类型元数据包含在线上,因为它不适用于平台之间。即使继承也不是核心protobuf规范的一部分。
protobuf-net作为特定实现引入了对继承的支持(通过一些冒烟和镜像),但理想情况下仍然可以提前定义预期类型 - 与其他序列化器完全相同例如XmlSerializer
或DataContractSerializer
。这可以通过使用[ProtoInclude(...)]
来指定预期的具体类型来完成。
如果您确实无法事先告知实际类型,则还有一个DynamicType
选项,它将AssemblyQualifiedName写入流中。如果您对此路由感兴趣,请注意该格式的“跨平台”功能开始崩溃,但它对.NET到.NET的用途非常有用。
最简单的一个包装器如:
[ProtoContract]
public class SomeWrapper {
[ProtoMember(1, DynamicType = true)]
public object Value {get;set;}
}
将对象包装在中并且它应该表现得很好(至少在v2中; v1中不存在DynamicType)。完整的例子:
[TestFixture]
public class SO7218127
{
[Test]
public void Test()
{
var orig = new SomeWrapper {Value = new SubType { Foo = 123, Bar = "abc"}};
var clone = Serializer.DeepClone(orig);
Assert.AreEqual(123, orig.Value.Foo);
Assert.AreEqual("abc", ((SubType) clone.Value).Bar);
}
[ProtoContract]
public class SomeWrapper
{
[ProtoMember(1, DynamicType = true)]
public BaseType Value { get; set; }
}
[ProtoContract]
public class BaseType
{
[ProtoMember(1)]
public int Foo { get; set; }
}
[ProtoContract]
public class SubType : BaseType
{
[ProtoMember(2)]
public string Bar { get; set; }
}
}