Protobuf.net序列化实现IEnumerable<T>的ObservableList类失败问题
Protobuf.net序列化实现IEnumerable的自定义类时属性丢失问题
问题场景
尝试使用最新版Protobuf.net序列化自定义ObservableList<T>类(实现IEnumerable<T>接口),类定义如下:
[ProtoContract(SkipConstructor = true)] public class ObservableList<T> : IEnumerable<T> { [ProtoMember(1)] private List<T> _list = new(); [ProtoMember(2)] private string _code; [ProtoMember(3)] private int _version; public string Code { get => _code; set => _code = value; } public int Version { get => _version; set => _version = value; } public IEnumerator<T> GetEnumerator() { return _list.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
执行测试时发现反序列化后Code属性为null,测试代码如下:
[Test] public void Test1() { var list = new ObservableList<string>(); list.Code = "FK1"; list.Version = 22; var ms = new MemoryStream(); ProtoBuf.Serializer.Serialize(ms, list); ms.Position = 0; var deserialized = ProtoBuf.Serializer.Deserialize<ObservableList<string>>(ms); Assert.AreEqual("FK1", deserialized.Code); // 此处失败,Code为null Assert.AreEqual(22, deserialized.Version); }
移除IEnumerable<T>接口后序列化恢复正常,需要排查原因并解决。
问题原因
Protobuf.net对实现IEnumerable<T>接口的类型有特殊处理逻辑:默认会将这类类型识别为集合类型,序列化时优先处理集合元素(即示例中的_list字段),同时自动忽略其他非集合相关的字段(_code、_version),导致这些属性在反序列化后无法正确恢复。
解决方法
方案1:禁用集合自动处理(推荐)
在[ProtoContract]特性中添加IgnoreListHandling = true参数,明确告诉Protobuf.net不要将该类当作集合类型处理,而是按普通类序列化所有标记了[ProtoMember]的字段:
[ProtoContract(SkipConstructor = true, IgnoreListHandling = true)] public class ObservableList<T> : IEnumerable<T> { // 原有代码保持不变 }
修改后重新执行测试,Code和Version属性都能正确序列化和反序列化。
方案2:调整序列化配置(备选)
如果无法修改类的特性,可以在序列化时通过RuntimeTypeModel手动配置,禁用该类型的集合处理:
RuntimeTypeModel.Default.Add(typeof(ObservableList<string>), false) .SetIgnoreListHandling(true);
这种方式适合无法修改类源码的场景。
内容的提问来源于stack exchange,提问作者Wolfgang
相关产品推荐
相关产品推荐

