.NET 5/.NET 6中如何反序列化二进制序列化的NameValueCollection?
在.NET 5/6中读取.NET Framework二进制序列化的NameValueCollection的可行方案
以下是无需依赖.NET Framework转换的几种解决方案:
方案1:自定义序列化代理类(利用ISerializable和SurrogateSelector)
通过创建匹配旧版NameValueCollection序列化结构的代理类,让BinaryFormatter用代理类替代新版类型完成反序列化,再转换为新版NameValueCollection。
实现代码
using System; using System.Collections; using System.Collections.Specialized; using System.Runtime.Serialization; [Serializable] public class LegacyNameValueCollectionSurrogate : ISerializable { private readonly NameValueCollection _collection; public LegacyNameValueCollectionSurrogate() { _collection = new NameValueCollection(); } // 核心:读取旧版序列化的私有字段 public LegacyNameValueCollectionSurrogate(SerializationInfo info, StreamingContext context) { _collection = new NameValueCollection(); // 对应.NET Framework中NameValueCollection的私有字段名,需与旧版本一致 var items = info.GetValue("_items", typeof(Hashtable)) as Hashtable; var allKeys = info.GetValue("_allKeys", typeof(string[])) as string[]; if (items != null && allKeys != null) { foreach (string key in allKeys) { if (key != null) { _collection[key] = items[key] as string; } } } } public void GetObjectData(SerializationInfo info, StreamingContext context) { // 仅用于反序列化场景,无需实现序列化逻辑 throw new NotImplementedException(); } // 转换为新版NameValueCollection public NameValueCollection ToNameValueCollection() => _collection; }
使用方式
using System.IO; using System.Runtime.Serialization.Formatters.Binary; public static NameValueCollection DeserializeLegacyNvc(byte[] serializedData) { var formatter = new BinaryFormatter(); var surrogateSelector = new SurrogateSelector(); // 注册代理:将新版NameValueCollection的序列化请求导向代理类 surrogateSelector.AddSurrogate( typeof(NameValueCollection), new StreamingContext(StreamingContextStates.All), new LegacyNameValueCollectionSurrogate()); formatter.SurrogateSelector = surrogateSelector; using var ms = new MemoryStream(serializedData); var surrogate = formatter.Deserialize(ms) as LegacyNameValueCollectionSurrogate; return surrogate?.ToNameValueCollection(); }
注意:需确认旧版
.NET Framework中NameValueCollection的私有字段名(可通过反编译旧版System.Collections.Specialized.dll验证),不同框架版本字段名可能存在差异。
方案2:手动解析二进制序列化流
直接解析二进制序列化的字节流,提取NameValueCollection的键值对数据。该方法需要熟悉.NET二进制序列化的格式规范,适合对性能要求较高或无法使用代理的场景。
核心步骤
- 跳过二进制流的头部类型描述信息,定位到存储
_items(Hashtable类型)和_allKeys(string[]类型)的位置; - 读取
Hashtable中的键值对集合,以及string[]中的所有键名; - 将读取到的键值对组装为新版
NameValueCollection。
此方法实现复杂度较高,需处理序列化格式中的类型标识、长度标记等细节,建议仅在其他方案不可行时使用。
方案3:加载.NET Framework兼容程序集
在.NET 5/6项目中加载.NET Framework版本的System.Collections.Specialized.dll,直接用旧版类型完成反序列化,再转换为新版集合。
实现步骤
- 从
.NET Framework 4.x安装目录(如C:\Windows\Microsoft.NET\Framework64\v4.0.30319)复制System.Collections.Specialized.dll到项目目录; - 在项目文件中添加配置启用运行时互操作:
<PropertyGroup> <DisableRuntimeMarshalling>false</DisableRuntimeMarshalling> </PropertyGroup>
- 添加对该dll的引用,设置“复制本地”为
true; - 编写反序列化代码:
using System; using System.IO; using System.Reflection; using System.Collections.Specialized; using System.Runtime.Serialization.Formatters.Binary; public static NameValueCollection DeserializeWithLegacyAssembly(byte[] serializedData) { var legacyAssembly = Assembly.LoadFrom("System.Collections.Specialized.dll"); var legacyNvcType = legacyAssembly.GetType("System.Collections.Specialized.NameValueCollection"); var formatter = new BinaryFormatter(); using var ms = new MemoryStream(serializedData); var legacyNvc = formatter.Deserialize(ms); // 反射读取旧版集合的键值对,转换为新版集合 var newCollection = new NameValueCollection(); var allKeys = legacyNvcType.GetProperty("AllKeys").GetValue(legacyNvc) as string[]; var getItemMethod = legacyNvcType.GetMethod("get_Item", new[] { typeof(string) }); foreach (var key in allKeys) { var value = getItemMethod.Invoke(legacyNvc, new object[] { key }) as string; newCollection[key] = value; } return newCollection; }
注意:此方法存在部署兼容性风险,需确保目标环境能正确加载旧版程序集,且可能受.NET版本策略限制。
内容的提问来源于stack exchange,提问作者oclipa
相关产品推荐
相关产品推荐

