飙血推荐
  • HTML教程
  • MySQL教程
  • JavaScript基础教程
  • php入门教程
  • JavaScript正则表达式运用
  • Excel函数教程
  • UEditor使用文档
  • AngularJS教程
  • ThinkPHP5.0教程

.NET Protobuf包装器库

时间:2021-12-04  作者:Kation  

Wodsoft Protobuf Wrapper

内容

  • 关于
  • 需求
  • 安装
  • 用法
    • 序列化
    • 反序列化
    • 字段定义
    • 字段排序
    • 非空构造函数对象
    • 获取Protobuf包装器
  • 高级
    • 支持的属性类型与Protobuf类型的关系
    • 如何工作
    • 性能
  • 许可证

关于

这是一个可以帮助你不需要.proto文件就能够使用Protobuf序列化的一个库。

通常.proto文件会创建继承IMessage接口的模型,Protobuf使用这些模型来进行序列化。

有时候我们已经在自己的.NET项目里创建了一些模型,但我们需要使用Protobuf对这些模型进行序列化。
这时候这个库就能帮助你使用Protobuf对已存在的模型进行序列化。

Github地址:域名per

需求

域名per需要NETStandard 2.0或以上。

这个库需要工作在允许动态代码编译的平台。所以IOS不支持

安装

在NuGet上获取域名per.

dotnet add package 域名per

用法

序列化

可以使用域名age类中的静态方法Serialize
你需要一个域名am来存储序列化后的数据。

YourModel model = new ();
MemoryStream stream = new MemoryStream();
域名alize(stream, model);

这里也有一个重载方法。
你可以传递一个域名dInputStream来替代域名am

YourModel model = new ();
CodedInputStream input = ...;
域名alize(input, model);

或者你想直接拿到序列化后的字节数组。

YourModel model = new ();
var bytes = 域名alizeToBytes(model);

反序列化

你可以使用域名age类中的静态方法Deserialize
你需要传递包含需要反序列化数据的域名am
它将返回你的泛型对象T

Stream stream = ...;
YourType model = 域名rialize<YourType>(stream);

这里也有一个重载方法。
你可以传递一个域名dOutputStream来替代域名am

CodedOutputStream output = ...;
YourType model = 域名rialize<YourType>(output);

或者你想直接从字节数组进行反序列化。

YourType model = 域名rializeFromBytes<YourType>(bytes);

字段定义

域名ields(Type type)会返回从对象映射而来的消息字段。

默认实现是域名nce类。
它只会映射可读写的属性到消息字段。

你可以创建自己的IMessageFieldProvider去映射消息字段。
然后通过设置静态属性Message<T>.FieldProvider为自定义的IMessageFieldProvider

你需要为每个需要自定义消息字段的类型设置IMessageFieldProvider

字段排序

给属性添加域名域名MemberAttribute特性然后设置Order属性。
不然将根据属性名称进行排序。

⚠️ 如果有任何一个属性使用了DataMemberAttribute特性,将只会序列化拥有DataMemberAttribute特性的属性。

⚠️ 如果全部没有使用DataMemberAttribute特性,服务如果因为部署问题使用了不同版本的模型,反序列化时可能因为字段排序问题存在错误。

非空构造函数

通过调用静态方法域名ypeInitializer<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(?) 域名stamp Length-delimited
DateTimeOffset(?) 域名stamp Length-delimited
TimeSpan(?) 域名tion 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<>可空类型。
  • 可以直接使用继承了域名sage的Protobuf对象作为属性类型。
  • 所有RepeatedFieldMapField对象不能包含null值。
  • 支持bytesbyteshortushort作为属性类型。
    它们将作为int类型进行序列化。
    如果从其它第三方来源数据进行反序列化,int可能会丢失数据。

如何工作

首先,Protobuf通过域名sage域名ferMessage接口进行序列化工作。

我们定义了一个抽象类域名age
然后定义抽象保护方法ReadWriteCalculateSize
显式实现这些接口并调用这些方法。

然后定义泛型抽象类域名age<T>
这里有一个属性可以直接获取到原始类型值。然后我们实现了一些隐式转换操作。

public T Source { get; }

最后,为需要序列化的类型动态创建继承了Message<T>的类。
通过Emit动态创建代码实现ReadWriteCalculateSize方法。

性能

  • 建议使用 RepeatedField<>IList<>ICollection<>作为集合属性的类型。
    使用RepeatedField<>会获得最佳性能(因为不需要额外类型转换)。
  • 使用IList<>ICollection<>在序列化时会转换为RepeatedField<>
  • 使用List<>Collection<>在序列化时会转换为RepeatedField<>
    并且在反序列化时会转换回List<>Collection<>(上一个会直接返回RepeatedField<>)。
  • 推荐使用 MapField<,>IDictionary<,>作为字典属性的类型。
    使用MapField<,>会获得最佳性能
  • 使用IDictionary<,>在序列化时会转换为MapField<,>
  • 使用Dictionary<,>在序列化时会转换为MapField<,>
    并且在反序列化时会转换回Dictionary<,>(上一个会直接返回MapField<,>)。

许可证

库使用MIT许可证。

标签:编程
湘ICP备14001474号-3  投诉建议:234161800@qq.com   部分内容来源于网络,如有侵权,请联系删除。