protobuf-net反序列化而不提供类型

时间:2014-12-03 10:10:09

标签: protobuf-net

为什么不提供输出类型就无法反序列化?

通常,如果两个端点正在通信,则两端共享相同的类型。在我的情况下,我在客户端和服务器应用程序上使用完全相同的库。在启动时,我在客户端和服务器上注册我的所有类型,如下所示:

 var metaType = RuntimeTypeModel.Default.Add( type, false );
 foreach( var prop in type.GetProperties() )
     metaType.Add( i++, prop.Name );

因此我希望protobuf能够在不提供类型的情况下尝试理解它应该反序列化的内容。 目前我正在使用它来反序列化:

RuntimeTypeModel.Default.DeserializeWithLengthPrefix(
    stream, null, type, ProtoBuf.PrefixStyle.Fixed32, 0 );

这种行为(也可以在其他序列化程序中找到)迫使我有一个超类型包装我要序列化的每个对象,其中我有实际的有效负载和一些其他信息,帮助我了解如何反序列化有效负载。所以我可以这样写:

public class MySuperType
{
    public byte[] Payload {get; set;}
    public Type PayloadType {get; set;} 
}

public object Deserialize( byte[] bytes )
{
    using( var stream = new MemoryStream( bytes ) )
    {
        var wrapperObject = Serializer.DeserializeWithLengthPrefix<MySupertype>
           ( stream, ProtoBuf.PrefixStyle.Fixed32 );

        using( var stream = new MemoryStream( wrapperObject.Payload ) )
        {
             var actualPayloadObject = RuntimeTypeModel.Default.DeserializeWithLengthPrefix(
                 stream, null, wrapperObject.PayloadType, ProtoBuf.PrefixStyle.Fixed32, 0 );

             return actualPayloadObject;
        }
    }    
}

所以我基本上知道我收到的每个对象都是MySupertype类型。 我把事情弄复了吗?

1 个答案:

答案 0 :(得分:1)

protobuf流指示根数据类型是不正常的。 期望调用代码知道数据的样子。但是,还有其他方法可以解决这个问题;例如,一种常见的方法是为每种类型指定一个标记号,并使用稍微复杂的序列化/反序列化重载来执行此查找 - 但是,这仍然需要代码来配置数字/类型之间的映射。

有时候更方便的方法通常是使用继承:

[ProtoContract]
[ProtoInclude(1, typeof(FooRequest))]
[ProtoInclude(2, typeof(BarRequest))]
public class RequestBase {}

public class FooRequest : RequestBase {...}
public class BarRequest : RequestBase {...}

这也避免了Type被序列化的需要,这是IMO不是一个好主意,并且在版本控制时可能会导致问题。有了上述内容,您可以始终使用RequestBase - 可能使用多态(virtualabstract方法)来获得有趣的代码。