C#通用序列化辅助类:XML、Binary与压缩实现

苏见山
苏见山
发布时间:2026-10-13 | 5人浏览过
原创

在C#开发中,面对需要持久化存储或跨网络传输的对象时,选择合适的序列化方式至关重要。本文分享一个通用的序列化辅助类(SerializeHelper),它整合了XML、SOAP及二进制格式的序列化能力,并结合DeflateStream实现了自动压缩与解压功能。该工具类不仅提供了丰富的类型转换支持,还包含了基于MemoryStream的对象克隆方法,能有效提升数据存储效率并确保数据一致性。

序列化技术选型与核心结构

在实际的.NET应用开发中,常见的序列化方案各有优劣。XmlSerializer生成的XML格式具有良好的可读性和跨平台兼容性,但执行效率相对较低且要求类型具备无参构造函数;SoapFormatter虽然能处理复杂引用,但在现代.NET Core/.NET 5+环境中已被标记为过时甚至移除,存在安全性风险;BinaryFormatter则拥有较高的性能和全面的类型支持,但由于其反序列化漏洞被广泛利用,Microsoft同样推荐使用[Serializable]替代并在新项目中标记为弃用。

本示例中的 SerializeHelper 类通过 SerializedType 枚举定义了包括字节数组、基本数值类型(Int, Double等)、布尔值以及压缩标识在内的多种数据状态,旨在通过统一的入口处理不同形态的数据输入,确保底层逻辑的复用性与扩展性。

环境准备与依赖项

在使用以下代码前,需确保项目已引入必要的命名空间,这些命名空间涵盖了文件操作、压缩算法及序列化核心库:

using System;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

注意:当前 .NET Standard 2.1 及 .NET 6/7/8 及以上版本默认不再包含 Sysytem.Runtime.Serialization.Formatters.Soap 和 System.Runtime.Serialization.Formatters.Binary 程序集的支持。若使用较新版本的 .NET SDK,可能需要额外添加对应的 NuGet 包引用来编译旧版参考代码。现代开发更建议转向 System.Text.Json 或 protobuf-net 以获得更好的性能与安全保证。

第1步:实现XML格式序列化与反序列化

XML序列化适用于需要将数据转换为文本文件进行人工调试或与其他系统交换数据的场景。此类通常分为“文件流直接写入”与“字符串转换”两种模式。

目的:将C#对象持久化为.xml文件,或从.xml字符串还原为对象。

关键操作:

  • Save方法:打开文件路径,实例化 XmlSerializer,并使用 serializer.Serialize() 将对象写入 FFileStream。需注意捕获异常并正确关闭文件句柄以防资源泄漏。
  • Load方法:以只读模式打开文件,实例化带有目标类型的 XmlSerializer,调用 Deserialize() 恢复对象。
  • ToXml / FromXml:利用 StringBuilder 和 StringReader 配合 XmlWriter 与 XmlReader,实现对象与XML文本字符串之间的无损互转。

第2步:处理SOAP及二进制(Binary)序列化

当对象结构较为复杂或涉及跨进程通信时,二进制序列化具有极高的压缩比和执行速度。尽管 BinaryFormatter 在新框架中被弃用,但其在遗留系统中的经典实现仍具参考价值。

目的:获取紧凑的二进制字节串,或者将二进制数据还原为原始对象。

核心步骤:

  1. 二进制的Hex字符串互转:通过 ToString("{0:X2}") 遍历 byte[] 数组将其转为Hex字符串存储,反序列化时再通过 Convert.ToInt32(str.Substring(...), 16) 重建字节流,便于在网络协议中传输。
  2. 文件级序列化:直接使用 FileMode.Create 建立文件流,交由 BinaryFormatter.Serialize() 完成物理写入,避免长时间占用内存。
  3. 字节大小计算:通过创建一个临时的空内存流进行“假序列化”,利用 memoryStream.Length 预先评估数据体积,以便决定后续是否启用压缩策略。

第3步:集成DeflateStream实现智能压缩

对于大型数据集,单纯的二进制序列化可能导致存储空间浪费。本工具类引入了 compressionThreshold 阈值参数,仅在数据超过设定大小时才触发压缩。

实现逻辑:

  • 压缩 (compress):创建内存流包裹 DeflateStream(设置 CompressionMode.Compress),将未压缩字节写入流中,读取输出流的完整缓冲区返回。
  • 解压 (decompress):使用相同的流机制,将 DeflateStream 设为 Decompress 模式,循环读取直至流结束,拼接还原后的字节数组。
  • 自动路由:主 Serialize() 方法根据 is 判断传入值的基元类型(如 int, double),或是复杂Object类型。若是Object类型且长度超限,则切换标签至 CompressedObject,确保反序列化时能够识别并解压。

第4步:利用序列化机制实现对象深拷贝(Clone)

在不改变对象内部属性的前提下,快速生成一个新的独立对象副本,是许多游戏引擎或缓存系统的需求。由于 BinaryFormatter 会递归遍历所有可序列化的字段,因此它是实现深拷贝的有效手段之一。

操作步骤:

  1. 输入:接收任意引用类型的对象 obj。
  2. 动作:创建空的 MemoryStream,调用 bFormatter.Serialize() 将对象状态Dump到内存块。
  3. 重置与输出:将流指针重设 SeekOrigin.Begin,再次调用 bFormatter.Deserialize()。此时内存流中解析出的新对象与原对象指向不同的堆地址,实现了真正的深拷贝。

注意事项与维护建议

虽然上述代码展示了C#底层的序列化工作原理,但在实际生产环境中应关注以下风险:

  • 安全风险:BinaryFormatter 和 S SoapFormatter 因缺乏对反序列化类的白名单校验,极易受到攻击。如果是新系统,请强烈建议使用 System.Text.Json。
  • 版本兼容:序列化协议一旦确定(特别是包含自定义类的对象),后续修改类的结构(如增加非默认构造方法的属性)往往会导致反序列化失败。务必保持数据契约的稳定。
  • 性能考量:频繁的小对象创建和GC回收可能成为瓶颈。在高性能场景下,结合 Buffers.SharedMemory 或使用 ProtoBuf 等零拷贝库会是更优选择。

以上就是C#实现的序列化通用类实例的详细内容,更多关于C# 序列化技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表