我在一个应用程序中使用protobuf-net,该应用程序对来自(出于所有意图和目的)第三方dll的对象进行了大量二进制序列化。结果,我不能在协定本身上使用[Proto-]属性,而是使用RuntimeTypeModel在运行时遇到新类型时准备序列化程序。序列化程序包装器示例:
public static class ProtobufSerializer
{
public static byte[] Serialize<T>(T obj)
{
PrepareSerializer(typeof(T));
ProtoBuf.Serialize(memoryStream, obj);
}
public static T Deserialize<T>(byte[] bytes)
{
PrepareSerializer(typeof(T));
ProtoBuf.Serialize(memoryStream, obj);
}
}
我们可以安全地假设PrepareSerializer
能够准备RuntimeTypeModel
来序列化任何给定类型。我在必须对DynamicType=true
进行对象反序列化时遇到一些问题。例如,给定以下接口:
public interface IFoo
{
string Name {get;}
}
执行:
public class Foo : IFoo
{
public string Name {get;set;}
public Bar Bar {get;set;}
[OnDeserializing]
public void OnDeserializing(Type t)
{
PrepareSerializer(typeof(Foo));
}
}
public class Bar
{
public int Baz {get;set;}
}
PrepareSerializer
方法本质上将使用代理并生成大致等效于以下模型的模型:
// registered surrogate for IFoo
[ProtoContract]
public class IFooSurrogate
{
[ProtoMember(1, DynamicType=true)]
public object Value
[OnSerializing]
public void OnSerializing(Type t)
{
PrepareSerializer(this.Value.GetType());
}
}
其中Value
由隐式转换器设置为等于IFoo的实例。这在序列化期间工作正常(在该事件被激发的情况下,我有机会为特定的接口实现类型准备序列化程序)。它在非分布式系统中也可以正常工作,在该系统中,我必须先尝试使用序列化方法,然后再尝试对该类型进行反序列化。但是,在分布式系统的反序列化过程中,当前节点以前从未见过Foo,ProtoBuf.Serializer在运行Foo.OnDeserializing事件之前抛出InvalidOperationException
抱怨类型Bar
缺少序列化程序。 (让我有机会告诉它如何反序列化Bar)。
在protobuf-net抱怨缺少序列化程序之前,有什么方法可以确保我的代码有机会了解'Foo'吗?
答案 0 :(得分:2)
我还没有尝试过这种情况,但是:为了提供一些灵活性,所有Type
的存储和补液都通过TypeModel.DynamicTypeFormatting
事件进行;因此,从理论上讲,您可以将事件挂在RuntimeTypeModel.Default
上,例如:
RuntimeTypeModel.DynamicTypeFormatting += (sender, args) => {
if (args.FormattedName != null) { // meaning: rehydrating
lock(SomeSyncLock) {
if(NotYetKnown(args.FormattedName))
Prepare(args.FormattedName);
}
}
};
该API的意图允许您控制如何解析类型,但是...我想它也可以解决此问题?
但是,我可以支持在第一次看到新的Type
时故意针对性更强的事件的想法,本质上是替换/补充了“应用默认行为”代码。不过,我认为它今天不存在。