0

0

C# protobuf-net使用方法 C#如何使用Protobuf进行高效序列化

畫卷琴夢

畫卷琴夢

发布时间:2026-01-30 09:39:10

|

758人浏览过

|

来源于php中文网

原创

protobuf-net序列化必须显式标注[ProtoContract]和[ProtoMember(n)],否则静默失败或抛出InvalidOperationException;仅支持已标记类型,需注意序号唯一性、泛型注册、流位置重置及线程安全。

c# protobuf-net使用方法 c#如何使用protobuf进行高效序列化

protobuf-net 序列化前必须标记 [ProtoContract][ProtoMember]

不加这些特性,Serializer.Serialize 会静默失败或抛出 InvalidOperationException:“No parameterless constructor defined”——哪怕类有默认构造函数。Protobuf-net 不依赖反射自动发现字段,它只序列化显式标注的成员。

常见错误是只给类加 [ProtoContract],却忘了给每个要序列化的字段/属性加 [ProtoMember(n)],其中 n 是唯一整数序号(不能重复,不能跳空,建议从 1 开始):

[ProtoContract]
public class Person
{
    [ProtoMember(1)] public string Name { get; set; }
    [ProtoMember(2)] public int Age { get; set; }
    [ProtoMember(3)] public DateTime BirthDate { get; set; }
}
  • 序号一旦发布就不要改,否则旧数据反序列化失败
  • 可读写属性、自动属性、私有字段都支持,但字段需加 private + [ProtoMember] 才生效
  • 不支持 dynamic、匿名类型、未标记的嵌套类

Serializer.SerializeSerializer.Deserialize 处理流

这是最轻量、最常用的 API,直接操作 Stream,无 JSON 或 XML 中间层,性能接近原生二进制。注意:它不处理编码、长度前缀、分帧,需要自己封装协议头。

典型用法:

var person = new Person { Name = "Alice", Age = 30 };
using var stream = new MemoryStream();
Serializer.Serialize(stream, person); // 写入
stream.Position = 0;
var deserialized = Serializer.Deserialize(stream); // 读回
  • 务必重置 stream.Position,否则 Deserialize 从末尾开始读,返回默认值
  • 避免对同一 Stream 多次复用而不清空或重置,容易因位置错乱导致反序列化失败
  • 如果要网络传输,推荐配合 SerializeWithLengthPrefix / DeserializeWithLengthPrefix 自动处理变长消息边界

泛型类型和集合要显式告知运行时类型

Protobuf-net 默认不支持开放泛型(如 List)或未实例化的泛型定义。遇到 NotSupportedException: Type is not expected, and no contract can be inferred 就是这个原因。

解决方式有两种:

  • 在类定义中用 [ProtoInclude] 预注册子类型(适合继承场景)
  • 对泛型集合,在序列化前调用 RuntimeTypeModel.Default.Add(typeof(List), true) 显式注册
  • 更稳妥的做法:使用具体封闭类型(如 List)并确保其元素类型已标记 [ProtoContract]

例如,以下写法会失败:

ViiTor AI
ViiTor AI

一个强大的多语言AI语音合成和视频转译平台

下载
[ProtoContract]
public class Container
{
    [ProtoMember(1)] public List Items; // ❌ object 无法推断具体类型
}

应改为:

[ProtoContract]
public class Container
{
    [ProtoMember(1)] public List People; // ✅ 类型明确且已注册
}

避免在 ASP.NET Core 中直接用 Serializer 替换 JSON 输出

有人试图在 Startup.ConfigureServices 里把 JsonSerializerOptions 换成 protobuf-net 的逻辑,这是行不通的。ASP.NET Core 的 IMvcBuilder.AddJsonOptions 只接受 JsonConverter,不兼容 protobuf-net 的二进制流。

若想全局启用 Protobuf 响应,正确路径是:

  • 实现自定义 OutputFormatter(继承 OutputFormatter),重写 CanWriteResultWriteResponseBody
  • 注册时指定 SupportedMediaTypes.Add("application/x-protobuf")
  • 客户端请求头需带 Accept: application/x-protobuf

别忽略 MIME 类型协商——Protobuf 不是浏览器原生支持的格式,纯前端调用基本不可行,主要用在后端服务间通信(gRPC 除外,那是另一套体系)。

真正容易被忽略的是线程安全性:RuntimeTypeModel.Default 是全局单例,首次访问会触发类型扫描和模型构建,后续并发调用是安全的;但如果你手动创建了多个 RuntimeTypeModel 实例,又没做好初始化同步,可能引发竞态或重复注册异常。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

419

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

535

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

311

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

77

2025.09.10

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1903

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2092

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

1076

2024.11.28

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

523

2023.08.10

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

0

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.6万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号