在C#开发场景中,数据序列化是服务间通信、本地数据持久化等场景的核心操作,传统的JSON、XML序列化方式虽然易用,但存在序列化速度慢、生成数据体积大的问题。protobuf-net是基于Google Protobuf协议的.NET生态高性能序列化库,相比传统序列化方式,它的序列化速度可提升数倍,生成的数据体积仅为JSON的1/3到1/2,非常适合对性能和传输效率要求较高的场景。

环境准备
首先需要在项目中引入protobuf-net库,最便捷的方式是通过NuGet包管理器安装,执行以下命令即可完成安装:
Install-Package protobuf-net
如果是.NET Core或者.NET 5及以上版本的项目,也可以使用dotnet cli命令安装:
dotnet add package protobuf-net
定义可序列化的实体类
protobuf-net需要通过特性标记来识别需要序列化的字段,核心特性是ProtoMember,用于指定字段的序列化编号,编号需要保证唯一且不可变更,否则会导致反序列化失败。下面是一个简单的用户实体类定义示例:
using ProtoBuf;
[ProtoContract]
public class User
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public int Age { get; set; }
[ProtoMember(4)]
public string Email { get; set; }
}
这里ProtoContract特性标记该类可以被protobuf-net序列化,每个ProtoMember后面的数字就是字段的唯一标识,编号从1开始递增即可,不需要连续。
序列化操作实现
序列化操作支持将对象转换为字节数组或者写入到流中,以下是两种常见的序列化实现方式:
序列化为字节数组
using System;
using ProtoBuf;
public class SerializeDemo
{
public static byte[] SerializeUser(User user)
{
using (var stream = new MemoryStream())
{
// 执行序列化,将对象写入流
Serializer.Serialize(stream, user);
// 返回流中的字节数组
return stream.ToArray();
}
}
}
序列化到文件流
using System.IO;
using ProtoBuf;
public class SerializeToFileDemo
{
public static void SerializeUserToFile(User user, string filePath)
{
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
Serializer.Serialize(fileStream, user);
}
}
}
反序列化操作实现
反序列化是序列化的逆过程,将字节数组或者流转换为对应的对象,实现方式如下:
从字节数组反序列化
using System;
using ProtoBuf;
public class DeserializeDemo
{
public static User DeserializeUser(byte[] data)
{
using (var stream = new MemoryStream(data))
{
// 执行反序列化,转换为User对象
return Serializer.Deserialize<User>(stream);
}
}
}
从文件流反序列化
using System.IO;
using ProtoBuf;
public class DeserializeFromFileDemo
{
public static User DeserializeUserFromFile(string filePath)
{
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
return Serializer.Deserialize<User>(fileStream);
}
}
}
完整使用示例
下面是一个完整的控制台程序示例,演示从创建对象、序列化、反序列化的完整流程:
using System;
using System.IO;
using ProtoBuf;
namespace ProtobufNetDemo
{
[ProtoContract]
public class User
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public int Age { get; set; }
[ProtoMember(4)]
public string Email { get; set; }
}
class Program
{
static void Main(string[] args)
{
// 创建测试对象
User user = new User
{
Id = 1,
Name = "张三",
Age = 25,
Email = "test@ipipp.com"
};
// 序列化为字节数组
byte[] data = SerializeUser(user);
Console.WriteLine($"序列化后字节数组长度:{data.Length}");
// 反序列化回对象
User deserializedUser = DeserializeUser(data);
Console.WriteLine($"反序列化结果:Id={deserializedUser.Id},Name={deserializedUser.Name},Age={deserializedUser.Age},Email={deserializedUser.Email}");
}
static byte[] SerializeUser(User user)
{
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, user);
return stream.ToArray();
}
}
static User DeserializeUser(byte[] data)
{
using (var stream = new MemoryStream(data))
{
return Serializer.Deserialize<User>(stream);
}
}
}
}
使用注意事项
ProtoMember的编号一旦确定不要随意修改,否则会导致旧数据无法反序列化。- 如果需要序列化集合类型,protobuf-net原生支持List、Dictionary等常见集合,不需要额外配置。
- 对于继承关系的实体类,需要使用
ProtoInclude特性标记子类,指定子类的唯一编号。 - 相比JSON序列化,protobuf-net生成的是二进制数据,可读性较差,调试时可以通过官方提供的工具转换为可读格式。
protobuf-netC#序列化反序列化修改时间:2026-07-20 06:12:29