运行时判断protobuf-net能否序列化/反序列化List等泛型类型的方案咨询
基于存储的类型名称判断protobuf-net可序列化的实现方案
实现思路
- 第一步:将数据库存储的程序集限定名称转换为
Type实例 - 第二步:递归判断类型是否满足protobuf-net序列化要求,补全原生方法缺少的泛型容器参数校验逻辑
代码实现
using ProtoBuf; using System; using System.Collections.Concurrent; using System.Linq; public static class ProtobufSerializationChecker { // 缓存校验结果,避免重复计算损耗性能 private static readonly ConcurrentDictionary<Type, bool> _checkCache = new ConcurrentDictionary<Type, bool>(); /// <summary> /// 根据存储的类型全限定名判断是否可被protobuf-net反序列化 /// </summary> public static bool CanDeserialize(string typeAssemblyQualifiedName) { try { var targetType = Type.GetType(typeAssemblyQualifiedName, throwOnError: false); if (targetType == null) return false; return IsProtobufSerializable(targetType); } catch { return false; } } private static bool IsProtobufSerializable(Type type) { if (_checkCache.TryGetValue(type, out var result)) return result; try { // 数组类型校验元素类型 if (type.IsArray) { var elementType = type.GetElementType(); result = elementType != null && IsProtobufSerializable(elementType); _checkCache.TryAdd(type, result); return result; } // 泛型类型先校验容器本身,再递归校验所有泛型参数 if (type.IsGenericType) { if (!Serializer.NonGeneric.CanSerialize(type)) { result = false; _checkCache.TryAdd(type, result); return result; } var genericArguments = type.GetGenericArguments(); result = genericArguments.All(IsProtobufSerializable); _checkCache.TryAdd(type, result); return result; } // 普通类型直接调用原生方法校验 result = Serializer.NonGeneric.CanSerialize(type); _checkCache.TryAdd(type, result); return result; } catch { result = false; _checkCache.TryAdd(type, result); return result; } } }
注意事项
- 原生
Serializer.NonGeneric.CanSerialize方法已经内置了自定义类型的ProtoContract特性校验、属性依赖类型的合法性校验,无需额外重复实现 - 若运行环境未默认加载对应类型的程序集,可在程序启动时注册
AppDomain.CurrentDomain.AssemblyResolve事件实现自定义程序集加载逻辑,避免类型加载失败 - 所有异常分支都做了静默处理返回不可序列化,可根据业务需要调整为抛出指定异常或增加日志记录
内容的提问来源于stack exchange,提问作者Sandy
相关产品推荐
相关产品推荐

