.NET 4.7与.NET 5.0跨版本反序列化List<IList>异常如何解决
问题根源
BinaryFormatter的序列化逻辑会把类型的完整强名称(包含所属程序集、版本、公钥标记)写入序列化结果,.NET 5+ 中包括IList在内的基础类型归属程序集从.NET Framework时代的mscorlib变为System.Private.CoreLib,跨版本反序列化时另一端无法识别对端的基础类型程序集标识,就会抛出找不到类型的异常。
过渡阶段兼容方案(支持逐个迁移应用)
方案1:自定义SerializationBinder做类型映射(推荐,成本最低)
不需要修改现有数据结构,也不需要兼容存量已序列化的文件,只需要在序列化/反序列化的两端都给BinaryFormatter绑定自定义的类型解析器,把跨版本的基础类型映射到当前运行时的对应类型即可,未更新的旧版本应用仍可正常互相通信。
自定义Binder代码如下,两端通用:
using System; using System.Reflection; using System.Runtime.Serialization; public class CrossRuntimeSerializationBinder : SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { string adjustedAssemblyName = assemblyName; string adjustedTypeName = typeName; // 处理.NET 5+的System.Private.CoreLib引用 if (assemblyName.Contains("System.Private.CoreLib")) { adjustedAssemblyName = typeof(IList).Assembly.FullName; adjustedTypeName = typeName.Replace("System.Private.CoreLib", typeof(IList).Assembly.GetName().Name); } // 处理.NET Framework的mscorlib引用 else if (assemblyName.Contains("mscorlib")) { adjustedAssemblyName = typeof(IList).Assembly.FullName; adjustedTypeName = typeName.Replace("mscorlib", typeof(IList).Assembly.GetName().Name); } // 优先用调整后的名称加载类型 Type type = Type.GetType($"{adjustedTypeName}, {adjustedAssemblyName}"); if (type != null) { return type; } // 兜底走默认加载逻辑 return Type.GetType($"{typeName}, {assemblyName}"); } }
使用方式,在序列化/反序列化的位置给BinaryFormatter指定Binder即可:
BinaryFormatter bf = new BinaryFormatter(); bf.Binder = new CrossRuntimeSerializationBinder(); // 新增此行即可 // 原有序列化/反序列化逻辑保持不变
方案2:禁用强名称验证
如果不想修改代码,也可以在.NET 5+应用的运行时配置文件中添加配置,让运行时忽略基础类型的强名称匹配,不过该方案灵活性较低,仅适合单向迁移的场景。
长期方案
微软已明确标记BinaryFormatter为不安全且过时的API,后续版本会默认禁用。全量迁移完成后建议替换为跨平台兼容的序列化方案:
- 结构化数据场景可使用
System.Text.Json或者Newtonsoft.Json - 二进制序列化需求可使用MessagePack、Protobuf等跨平台序列化框架
内容的提问来源于stack exchange,提问作者Q-bertsuit
相关产品推荐
相关产品推荐

