Protobuf-net序列化含接口的复杂数据结构报错,如何解决?
问题描述
我定义了接口iTest,其实现类anImplemntation在简单场景下可以单独序列化,也能作为testParent类的成员完成序列化,示例代码如下:
static void testSerializeInterface() { var ai = new anImplemntation(); ai.aVal = 101; var tp = new testParent(); tp.aTest = ai; MemoryStream msTEMP = new MemoryStream(); Serializer.Serialize(msTEMP, ai); } interface iTest { void Go(); } [ProtoContract] class anImplemntation:iTest { [ProtoMember(1)] public int aVal; public void Go() { } } [ProtoContract] class testParent { [ProtoMember(1)] public iTest aTest; }
但当使用包含大量Dictionary和接口类型List的复杂数据结构时,序列化会报错“unexpected sub-type anImplemntation”;以下是最小复现示例,运行时会出现“No serializer or type iTest is available to model (default)”错误,请问该如何解决?
public static void testSerializeInterface() { var ai = new anImplemntation(); var tp = new testParent(); tp.aTest = ai; ai.aList.Add(new anImplemntation()); MemoryStream ms = new MemoryStream(); Serializer.Serialize(ms, ai); } interface iTest { void Go(); } [ProtoContract] class anImplemntation : iTest { [ProtoMember(1)] public int aVal; [ProtoMember(2)] public List<iTest> aList = new List<iTest>(); public void Go() { } } [ProtoContract] class testParent { [ProtoMember(1)] public iTest aTest; }
解决方案
Protobuf-net无法自动推断接口对应的具体实现类,必须显式告知序列化器接口与实现类的映射关系,以下是两种可行方案:
方案一:通过特性配置已知类型
给iTest接口添加[ProtoContract]特性,并使用[ProtoInclude]指定它的实现类,示例代码如下:
[ProtoContract] [ProtoInclude(100, typeof(anImplemntation))] // 100为唯一标识号,需避开类成员的ProtoMember编号 interface iTest { void Go(); }
这样序列化器处理List<iTest>这类接口类型集合时,就能正确识别对应的实现类。
方案二:通过RuntimeTypeModel注册映射
若无法修改接口特性(比如接口属于第三方库),可在序列化操作前,通过RuntimeTypeModel手动注册接口与实现类的关系,代码如下:
// 建议在程序初始化阶段执行一次 RuntimeTypeModel.Default.Add(typeof(iTest), false) .AddSubType(100, typeof(anImplemntation));
注意事项
[ProtoInclude]或注册时使用的标识号(如示例中的100)不能与类中[ProtoMember]的编号重复,建议从100开始分配这类编号,避免冲突。- 若接口有多个实现类,需为每个实现类添加对应的
[ProtoInclude]特性或注册条目。
内容的提问来源于stack exchange,提问作者mcmillab
相关产品推荐
相关产品推荐

