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

在 C# 开发中,序列化是对象与数据之间桥梁式的存在,广泛应用于数据存储、网络传输、远程通信等场景。

序列化:将数据结构或对象状态转换为可存储或可传输的格式的过程。这个过程将内存中的对象转换为字节序列,可以写入文件、数据库或通过网络传输。

反序列化:序列化的逆过程,将序列化的数据重新构建为内存中的对象,恢复其原始状态和结构。

1. BinaryFormatter —— 经典但已被淘汰的序列化工具

✅ 简介

BinaryFormatter 是 .NET Framework 中最早期的序列化工具之一,能将对象直接转为二进制流,适合本地持久化、进程间通信等用途。

[Serializable]
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// 序列化
using (var stream = new FileStream("person.bin", FileMode.Create))
{
    var formatter = new BinaryFormatter();
    formatter.Serialize(stream, new Person { Name = "Alice", Age = 30 });
}

// 反序列化
using (var stream = new FileStream("person.bin", FileMode.Open))
{
    var formatter = new BinaryFormatter();
    var person = (Person)formatter.Deserialize(stream);
}

❌ 存在的问题

  • 存储数据包含完整类型信息,存在反序列化攻击风险

  • 序列化后的数据与平台强绑定,不具备跨语言能力(比如反序列化时,程序集名称必须和系列化时一致

  • Microsoft 在 .NET 5+ 明确弃用它,且在.NET 7中完全禁用默认使用

2. System.Text.Json —— 现代 .NET 推荐方案

✅ 简介

System.Text.Json 是 .NET Core 3.0 起官方推出的高性能 JSON 序列化库,替代了之前广泛使用的 Newtonsoft.Json,性能更好、原生支持 Span<T>UTF-8

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// 序列化
string json = JsonSerializer.Serialize(new Person { Name = "Bob", Age = 25 });

// 反序列化
Person person = JsonSerializer.Deserialize<Person>(json);

✅ 特点

  • 人类可读的 JSON 格式,调试友好

  • 无需标记属性,默认即可工作

  • 性能优于 Newtonsoft.Json

  • 支持 ASP.NET Core 原生绑定

✅ 适合场景

  • Web API 请求/响应体序列化

  • 日志记录、配置文件

  • 跨平台、语言间 JSON 通信

3. Protocol Buffers(Protobuf)—— 高性能二进制序列化

✅ 简介

Protobuf 是 Google 开发的跨平台、高性能、紧凑型二进制序列化协议,适用于对性能敏感、带宽有限的场景。它需要定义 .proto 文件,然后用工具生成 C# 类。

示例 .proto 文件:

syntax = "proto3";

message Person {
  string name = 1;
  int32 age = 2;
}

生成并使用 C# 代码:

using var stream = File.Create("person.pb");
Person person = new Person { Name = "Charlie", Age = 28 };
person.WriteTo(stream);

// 反序列化
using var input = File.OpenRead("person.pb");
Person parsed = Person.Parser.ParseFrom(input);
✅ 特点
  • 二进制编码,占用空间小,速度极快

  • 强类型,严格结构控制

  • 向后/向前兼容性好(字段编号)

  • 跨语言支持广泛(Java、Python、C++、Go 等)

✅ 适合场景

  • 微服务通信(如 gRPC)

  • 嵌入式设备、移动端

  • 高吞吐、高并发应用

4. 总结

大小和速度对比测试

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

  • 解压后,把 bin 文件夹路径加入到环境变量中

(2)用 protoc 生成 C# 文件:

protoc --csharp_out=. Person.proto

(3)代码

using System.Diagnostics;
using System.Text.Json;
using Google.Protobuf;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    const int Iterations = 10000;

    static void Main()
    {
        var person = new Person { Name = "Alice", Age = 30 };
        var personProto = new PersonMessage { Name = "Alice", Age = 30 };

        Console.WriteLine("Running serialization benchmarks...\n");

        Benchmark("System.Text.Json", () =>
        {
            return JsonSerializer.SerializeToUtf8Bytes(person);
        }, bytes => {
            JsonSerializer.Deserialize<Person>(bytes);
        });

        Benchmark("Protocol Buffers", () =>
        {
            using var ms = new MemoryStream();
            personProto.WriteTo(ms);
            return ms.ToArray();
        }, bytes => {
            PersonMessage.Parser.ParseFrom(bytes);
        });
    }

    static void Benchmark(string name, Func<byte[]> serialize, Action<byte[]> deserialize)
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        byte[] result = null;
        Stopwatch sw = new Stopwatch();

        // Serialize
        sw.Start();
        for (int i = 0; i < Iterations; i++)
        {
            result = serialize();
        }
        sw.Stop();
        long serializeTime = sw.ElapsedMilliseconds;

        // Deserialize
        sw.Restart();
        for (int i = 0; i < Iterations; i++)
        {
            deserialize(result);
        }
        sw.Stop();
        long deserializeTime = sw.ElapsedMilliseconds;

        double avgSerialize = serializeTime * 1000.0 / Iterations;     // 微秒
        double avgDeserialize = deserializeTime * 1000.0 / Iterations; // 微秒

        Console.WriteLine($"[{name}]");
        Console.WriteLine($"  Serialized Size: {result.Length} bytes");
        Console.WriteLine($"  Avg Serialize Time:   {avgSerialize:F2} µs");
        Console.WriteLine($"  Avg Deserialize Time:   {avgDeserialize:F2} µs\n");
    }

}
View Code
Running serialization benchmarks...

[System.Text.Json]
  Serialized Size: 25 bytes
  Avg Serialize Time:   5.50 μs
  Avg Deserialize Time:   0.80 μs

[Protocol Buffers]
  Serialized Size: 9 bytes
  Avg Serialize Time:   0.70 μs
  Avg Deserialize Time:   0.30 μs

 总结

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

如何选择?

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

 

posted @ 2025-05-08 09:30  湾仔码农  阅读(229)  评论(0)    收藏  举报