.NET Protobuf包装器库
Wodsoft Protobuf Wrapper
内容
关于
这是一个可以帮助你不需要.proto文件就能够使用Protobuf序列化的一个库。
通常.proto文件会创建继承IMessage接口的模型,Protobuf使用这些模型来进行序列化。
有时候我们已经在自己的.NET项目里创建了一些模型,但我们需要使用Protobuf对这些模型进行序列化。
这时候这个库就能帮助你使用Protobuf对已存在的模型进行序列化。
Github地址:Wodsoft.Protobuf.Wrapper
需求
Wodsoft.Protobuf.Wrapper需要NETStandard 2.0或以上。
这个库需要工作在允许动态代码编译的平台。所以IOS不支持。
安装
在NuGet上获取Wodsoft.Protobuf.Wrapper.
dotnet add package Wodsoft.Protobuf.Wrapper
用法
序列化
可以使用Wodsoft.Protobuf.Message
类中的静态方法Serialize
。
你需要一个System.IO.Stream
来存储序列化后的数据。
YourModel model = new ();
MemoryStream stream = new MemoryStream();
Message.Serialize(stream, model);
这里也有一个重载方法。
你可以传递一个Google.Protobuf.CodedInputStream
来替代System.IO.Stream
。
YourModel model = new ();
CodedInputStream input = ...;
Message.Serialize(input, model);
或者你想直接拿到序列化后的字节数组。
YourModel model = new ();
var bytes = Message.SerializeToBytes(model);
反序列化
你可以使用Wodsoft.Protobuf.Message
类中的静态方法Deserialize
。
你需要传递包含需要反序列化数据的System.IO.Stream
。
它将返回你的泛型对象T
。
Stream stream = ...;
YourType model = Message.Deserialize<YourType>(stream);
这里也有一个重载方法。
你可以传递一个Google.Protobuf.CodedOutputStream
来替代System.IO.Stream
。
CodedOutputStream output = ...;
YourType model = Message.Deserialize<YourType>(output);
或者你想直接从字节数组进行反序列化。
YourType model = Message.DeserializeFromBytes<YourType>(bytes);
字段定义
IMessageFieldProvider.GetFields(Type type)
会返回从对象映射而来的消息字段。
默认实现是GeneralMessageFieldProvider.Intance
类。
它只会映射可读写的属性到消息字段。
你可以创建自己的IMessageFieldProvider
去映射消息字段。
然后通过设置静态属性Message<T>.FieldProvider
为自定义的IMessageFieldProvider
。
你需要为每个需要自定义消息字段的类型设置
IMessageFieldProvider
。
字段排序
给属性添加System.Runtime.Serialization.DataMemberAttribute
特性然后设置Order
属性。
不然将根据属性名称进行排序。
️ 如果有任何一个属性使用了
DataMemberAttribute
特性,将只会序列化拥有DataMemberAttribute
特性的属性。
️ 如果全部没有使用
DataMemberAttribute
特性,服务如果因为部署问题使用了不同版本的模型,反序列化时可能因为字段排序问题存在错误。
非空构造函数
通过调用静态方法MessageBuilder.SetTypeInitializer<T>(Func<T> initializer)
来设置对象初始化委托。
获取Protobuf包装器
我们可以直接转换模型对象为Message<>
。
SimplyModel model;
Message<SimplyModel> message = model;
然后这个message
可以直接被Protobuf序列化。
高级
支持的属性类型与Protobuf类型的关系
C#类型 | Protobuf类型 | 消息结构 |
---|---|---|
bool(?) | bool | Varint |
sbyte(?) | int32 | Varint |
byte(?) | int32 | Varint |
short(?) | int32 | Varint |
ushort(?) | int32 | Varint |
int(?) | int32 | Varint |
long(?) | int64 | Varint |
uint(?) | uint32 | Varint |
ulong(?) | uint64 | Varint |
float(?) | float | Varint |
double(?) | double | Varint |
string | string | Length-delimited |
byte[] | ByteString | Length-delimited |
Guid(?) | ByteString | Length-delimited |
DateTime(?) | google.protobuf.Timestamp | Length-delimited |
DateTimeOffset(?) | google.protobuf.Timestamp | Length-delimited |
TimeSpan(?) | google.protobuf.Duration | Length-delimited |
IMessage | Length-delimited | |
T[] | RepeatedField<T> | Length-delimited |
ICollection<T> | RepeatedField<T> | Length-delimited |
Collection<T> | RepeatedField<T> | Length-delimited |
IList<T> | RepeatedField<T> | Length-delimited |
List<T> | RepeatedField<T> | Length-delimited |
IDictionary<TKey, TValue> | MapField<TKey, TValue> | Length-delimited |
Dictionary<TKey, TValue> | MapField<TKey, TValue> | Length-delimited |
- (?) 意思是可以为
Nullable<>
可空类型。 - 可以直接使用继承了
Google.Protobuf.IMessage
的Protobuf对象作为属性类型。 - 所有
RepeatedField
与MapField
对象不能包含null
值。 - 支持
byte
,sbyte
,short
和ushort
作为属性类型。
它们将作为int
类型进行序列化。
如果从其它第三方来源数据进行反序列化,int
可能会丢失数据。
如何工作
首先,Protobuf通过Google.Protobuf.IMessage
与Google.Protobuf.IBufferMessage
接口进行序列化工作。
我们定义了一个抽象类Wodsoft.Protobuf.Message
。
然后定义抽象保护方法Read
,Write
,CalculateSize
。
显式实现这些接口并调用这些方法。
然后定义泛型抽象类Wodsoft.Protobuf.Message<T>
。
这里有一个属性可以直接获取到原始类型值。然后我们实现了一些隐式转换操作。
public T Source { get; }
最后,为需要序列化的类型动态创建继承了Message<T>
的类。
通过Emit动态创建代码实现Read
,Write
,CalculateSize
方法。
性能
- 建议使用
RepeatedField<>
,IList<>
或ICollection<>
作为集合属性的类型。
使用RepeatedField<>
会获得最佳性能(因为不需要额外类型转换)。 - 使用
IList<>
或ICollection<>
在序列化时会转换为RepeatedField<>
。 - 使用
List<>
或Collection<>
在序列化时会转换为RepeatedField<>
。
并且在反序列化时会转换回List<>
或Collection<>
(上一个会直接返回RepeatedField<>
)。 - 推荐使用
MapField<,>
或IDictionary<,>
作为字典属性的类型。
使用MapField<,>
会获得最佳性能。 - 使用
IDictionary<,>
在序列化时会转换为MapField<,>
。 - 使用
Dictionary<,>
在序列化时会转换为MapField<,>
。
并且在反序列化时会转换回Dictionary<,>
(上一个会直接返回MapField<,>
)。
许可证
库使用MIT许可证。
.NET Protobuf包装器库的更多相关文章
- java基础类型、包装器
char a = 'h'; //类包装器 Character aobj = a ;//自动装箱 byte b = 6; Byte bobj = b; short s = 234; Short sob ...
- C++11多态函数对象包装器
[C++11多态函数对象包装器] 针对函数对象的多态包装器(又称多态函数对象包装器)在语义和语法上和函数指针相似,但不像函数指针那么狭隘.只要能被调用,且其参数能与包装器兼容的都能以多态函数对象包装器 ...
- ACE的包装器
ACE大量运用包装器模式,以期改变面向过程的系统API可视性以及错误处理较难的情况 包装器在若干场合能极大简化代码量,甚至是编码过程 比如ACE_Thread_Mutex 对象创建会自动初始化,很开心 ...
- Java中基本数据类型和包装器类型的关系
在程序设计中经常用到一系列的数据类型,在Java中也一样包含八中数据类型,这八种数据类型又各自对应一种包装器类型.如下表: 基本类型 包装器类型 boolean Boolean char Charac ...
- Java 装箱、拆箱 包装器
先说java的基本数据类型.java基本数据类型:byte.short.int.long.float.double.char.boolean 基本数据类型的自动装箱(autoboxing).拆箱(un ...
- 翻译:探索GLSL-用几何着色器(着色器库)实现法线可视化
翻译:探索GLSL-用几何着色器(着色器库)实现法线可视化 翻译自: Exploring GLSL – Normal Visualizer with Geometry Shaders (Shader ...
- 【Head First Servlets and JSP】笔记 28: 过滤器与包装器
1.过滤器的执行顺序: <url-pattern> 为第一梯队, <servlet-name> 为第二梯队,梯队内的执行顺序和 DD 里的声明顺序相同. When the co ...
- java基本类型和包装器类
java是一种面向对象语言,java中的类把方法与数据连接在一起,并构成了自包含式的处理单元.但在java中不能定义基本类型(primitive type),为了能将基本类型视为对象来处理,并能连接相 ...
- 【Keras案例学习】 sklearn包装器使用示范(mnist_sklearn_wrapper)
import numpy as np from keras.datasets import mnist from keras.models import Sequential from keras.l ...
随机推荐
- GKCTF 2021 Reverse Writeup
前言 GKCTF 2021所以题目均以开源,下面所说的一切思路可以自行通过源码对比IDA进行验证. Github项目地址:https://github.com/w4nd3r-0/GKCTF2021 出 ...
- 数据结构与算法——弗洛伊德(Floyd)算法
介绍 和 Dijkstra 算法一样,弗洛伊德(Floyd)算法 也是一种用于寻找给定的加权图中顶点间最短路径的算法.该算法名称以创始人之一.1978 年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特 ...
- Bert文本分类实践(一):实现一个简单的分类模型
写在前面 文本分类是nlp中一个非常重要的任务,也是非常适合入坑nlp的第一个完整项目.虽然文本分类看似简单,但里面的门道好多好多,作者水平有限,只能将平时用到的方法和trick在此做个记录和分享,希 ...
- C++学习 1 数组
一维数组: 定义:1.数据类型 数组名 [ 数组长度 ]: int arr [5];//赋值 arr[0]=10; arr[1]=20; arr[2]=30; arr[3]=40; arr[4]=50 ...
- Serverless 在 SaaS 领域的最佳实践
作者 | 计缘 来源 | Serverless 公众号 随着互联网人口红利逐渐减弱,基于流量的增长已经放缓,互联网行业迫切需要找到一片足以承载自身持续增长的新蓝海,产业互联网正是这一宏大背景下的新趋势 ...
- LeetCode:数组专题
数组专题 有关数组的一些 leetcode 题,在此做一些记录,不然没几天就忘光光了 二分查找 双指针 滑动窗口 前缀和/差分数组 二分查找 本文内容摘录自公众号labuladong中有关二分查找的文 ...
- 5.31日 Scrum Metting
日期:2021年5月31日 会议主要内容概述:讨论草稿箱前后端接口,讨论账单页面设计. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 文件导入功能 ...
- “妈妈再也不用担心我忘交作业了!”——记2020BUAA软工团队项目选择
写在前面 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 团队项目选择 项目简介 项目名称:北航学生资源整合和作业提醒平台 项目内容: 设计实现一 ...
- NKOJ1828 Feed Ratios饲料调配
题目 好题!高斯消元切了! (其实只是单纯地想吐槽这道出现在"高斯消元"专练里的题,暴搜能过,goudoubuxie"Gauss") 下面是暴搜: #pragm ...
- BOOST内存管理-intrusive_ptr
参考链接https://blog.csdn.net/harbinzju/article/details/6754646 intrusive_ptr 是shared_ptr的插入式版本.与shared_ ...