为什么不提供输出类型就无法反序列化?
通常,如果两个端点正在通信,则两端共享相同的类型。在我的情况下,我在客户端和服务器应用程序上使用完全相同的库。在启动时,我在客户端和服务器上注册我的所有类型,如下所示:
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类型。 我把事情弄复了吗?
答案 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
- 可能使用多态(virtual
或abstract
方法)来获得有趣的代码。