2011-08-27 84 views
1

我已经开发了一个应用程序,旨在发送数据从客户端到服务器和回等使用序列化的对象。Protobuf网例外与未知的子类

对于这个应用程序,我决定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是基于合同的序列化格式,设计为独立于平台。因此,类型元数据包含在网络中,因为它不适用于平台之间。即使继承不是核心protobuf规范的一部分。

protobuf网作为具体实施引入了继承支持(通过一些烟雾和镜子),但理想的应该还是可以预先定义预期的类型 - 完全一样,其他串行如XmlSerializerDataContractSerializer。这可以通过使用[ProtoInclude(...)]来指定预期的具体类型来完成。

如果您确实无法预先告知实际类型,还有一个DynamicType选项,该选项将AssemblyQualifiedName写入流中。如果你对这条路线感兴趣,那么请注意格式的“跨平台”功能开始崩溃,但它对于.NET到.NET的目的非常有用。

在最简单的,一个包装如:

[ProtoContract] 
public class SomeWrapper { 
    [ProtoMember(1, DynamicType = true)] 
    public object Value {get;set;} 
} 

总结你的对象是它应该表现(在V2中至少一个; DynamicType并未V1存在)。完整示例:

[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; } 
    } 
}