找回密码
 立即注册
首页 业界区 安全 C#序列化技术:BinaryFormatter、System.Text.Json、Pro ...

C#序列化技术:BinaryFormatter、System.Text.Json、Protocol Buffers

骆贵 6 天前
在 C# 开发中,序列化是对象与数据之间桥梁式的存在,广泛应用于数据存储、网络传输、远程通信等场景。
序列化:将数据结构或对象状态转换为可存储或可传输的格式的过程。这个过程将内存中的对象转换为字节序列,可以写入文件、数据库或通过网络传输。
反序列化:序列化的逆过程,将序列化的数据重新构建为内存中的对象,恢复其原始状态和结构。
1. BinaryFormatter —— 经典但已被淘汰的序列化工具

✅ 简介

BinaryFormatter 是 .NET Framework 中最早期的序列化工具之一,能将对象直接转为二进制流,适合本地持久化、进程间通信等用途。
  1. [Serializable]
  2. public class Person
  3. {
  4.     public string Name { get; set; }
  5.     public int Age { get; set; }
  6. }
  7. // 序列化
  8. using (var stream = new FileStream("person.bin", FileMode.Create))
  9. {
  10.     var formatter = new BinaryFormatter();
  11.     formatter.Serialize(stream, new Person { Name = "Alice", Age = 30 });
  12. }
  13. // 反序列化
  14. using (var stream = new FileStream("person.bin", FileMode.Open))
  15. {
  16.     var formatter = new BinaryFormatter();
  17.     var person = (Person)formatter.Deserialize(stream);
  18. }
复制代码
❌ 存在的问题


  • 存储数据包含完整类型信息,存在反序列化攻击风险
  • 序列化后的数据与平台强绑定,不具备跨语言能力(比如反序列化时,程序集名称必须和系列化时一致
  • Microsoft 在 .NET 5+ 明确弃用它,且在.NET 7中完全禁用默认使用
2. System.Text.Json —— 现代 .NET 推荐方案

✅ 简介

System.Text.Json 是 .NET Core 3.0 起官方推出的高性能 JSON 序列化库,替代了之前广泛使用的 Newtonsoft.Json,性能更好、原生支持 Span 与 UTF-8。
  1. public class Person
  2. {
  3.     public string Name { get; set; }
  4.     public int Age { get; set; }
  5. }
  6. // 序列化
  7. string json = JsonSerializer.Serialize(new Person { Name = "Bob", Age = 25 });
  8. // 反序列化
  9. Person person = JsonSerializer.Deserialize<Person>(json);
复制代码
✅ 特点


  • 人类可读的 JSON 格式,调试友好
  • 无需标记属性,默认即可工作
  • 性能优于 Newtonsoft.Json
  • 支持 ASP.NET Core 原生绑定
✅ 适合场景


  • Web API 请求/响应体序列化
  • 日志记录、配置文件
  • 跨平台、语言间 JSON 通信
3. Protocol Buffers(Protobuf)—— 高性能二进制序列化

✅ 简介

Protobuf 是 Google 开发的跨平台、高性能、紧凑型二进制序列化协议,适用于对性能敏感、带宽有限的场景。它需要定义 .proto 文件,然后用工具生成 C# 类。
示例 .proto 文件:
  1. syntax = "proto3";
  2. message Person {
  3.   string name = 1;
  4.   int32 age = 2;
  5. }
复制代码
生成并使用 C# 代码:
  1. using var stream = File.Create("person.pb");
  2. Person person = new Person { Name = "Charlie", Age = 28 };
  3. person.WriteTo(stream);
  4. // 反序列化
  5. using var input = File.OpenRead("person.pb");
  6. Person parsed = Person.Parser.ParseFrom(input);
复制代码
✅ 特点

  • 二进制编码,占用空间小,速度极快
  • 强类型,严格结构控制
  • 向后/向前兼容性好(字段编号)
  • 跨语言支持广泛(Java、Python、C++、Go 等)
✅ 适合场景


  • 微服务通信(如 gRPC)
  • 嵌入式设备、移动端
  • 高吞吐、高并发应用
4. 总结

大小和速度对比测试

(1)windows安装 Protocol Buffers 编译器 (protoc)

  • 前往官网下载编译器 zip 包


  • 解压后,把 bin 文件夹路径加入到环境变量中
(2)用 protoc 生成 C# 文件:
  1. protoc --csharp_out=. Person.proto
复制代码
(3)代码
1.gif
2.gif
  1. using System.Diagnostics;
  2. using System.Text.Json;
  3. using Google.Protobuf;
  4. public class Person
  5. {
  6.     public string Name { get; set; }
  7.     public int Age { get; set; }
  8. }
  9. class Program
  10. {
  11.     const int Iterations = 10000;
  12.     static void Main()
  13.     {
  14.         var person = new Person { Name = "Alice", Age = 30 };
  15.         var personProto = new PersonMessage { Name = "Alice", Age = 30 };
  16.         Console.WriteLine("Running serialization benchmarks...\n");
  17.         Benchmark("System.Text.Json", () =>
  18.         {
  19.             return JsonSerializer.SerializeToUtf8Bytes(person);
  20.         }, bytes => {
  21.             JsonSerializer.Deserialize<Person>(bytes);
  22.         });
  23.         Benchmark("Protocol Buffers", () =>
  24.         {
  25.             using var ms = new MemoryStream();
  26.             personProto.WriteTo(ms);
  27.             return ms.ToArray();
  28.         }, bytes => {
  29.             PersonMessage.Parser.ParseFrom(bytes);
  30.         });
  31.     }
  32.     static void Benchmark(string name, Func<byte[]> serialize, Action<byte[]> deserialize)
  33.     {
  34.         GC.Collect();
  35.         GC.WaitForPendingFinalizers();
  36.         GC.Collect();
  37.         byte[] result = null;
  38.         Stopwatch sw = new Stopwatch();
  39.         // Serialize
  40.         sw.Start();
  41.         for (int i = 0; i < Iterations; i++)
  42.         {
  43.             result = serialize();
  44.         }
  45.         sw.Stop();
  46.         long serializeTime = sw.ElapsedMilliseconds;
  47.         // Deserialize
  48.         sw.Restart();
  49.         for (int i = 0; i < Iterations; i++)
  50.         {
  51.             deserialize(result);
  52.         }
  53.         sw.Stop();
  54.         long deserializeTime = sw.ElapsedMilliseconds;
  55.         double avgSerialize = serializeTime * 1000.0 / Iterations;     // 微秒
  56.         double avgDeserialize = deserializeTime * 1000.0 / Iterations; // 微秒
  57.         Console.WriteLine($"[{name}]");
  58.         Console.WriteLine($"  Serialized Size: {result.Length} bytes");
  59.         Console.WriteLine($"  Avg Serialize Time:   {avgSerialize:F2} µs");
  60.         Console.WriteLine($"  Avg Deserialize Time:   {avgDeserialize:F2} µs\n");
  61.     }
  62. }
复制代码
View Code
  1. Running serialization benchmarks...
  2. [System.Text.Json]
  3.   Serialized Size: 25 bytes
  4.   Avg Serialize Time:   5.50 μs
  5.   Avg Deserialize Time:   0.80 μs
  6. [Protocol Buffers]
  7.   Serialized Size: 9 bytes
  8.   Avg Serialize Time:   0.70 μs
  9.   Avg Deserialize Time:   0.30 μs
复制代码
 总结

特性BinaryFormatterSystem.Text.JsonProtocol Buffers数据格式二进制(含类型信息)JSON 文本紧凑型二进制格式性能中中-高高安全性❌ 存在严重安全风险✅ 安全✅ 安全可读性❌✅ 人类可读❌跨平台/跨语言支持❌⚠ 有限(需字段兼容)✅ 强推荐使用❌ 不推荐✅ 推荐✅ 推荐

如何选择?

需求场景推荐序列化技术高性能通信、跨语言✅ ProtobufWeb 服务、API 接口✅ System.Text.Json本地临时存储(可读性优先)✅ System.Text.Json旧项目中偶尔仍需使用⚠ BinaryFormatter(需谨慎) 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册