关于
需求
安装
用法
序列化
反序列化
字段定义
字段排序
非空构造函数对象
获取Protobuf包装器
高级
支持的属性类型与Protobuf类型的关系
如何工作
性能
许可证
这是一个可以帮助你不需要.proto文件就能够使用Protobuf序列化的一个库。
通常.proto文件会创建继承IMessage接口的模型,Protobuf使用这些模型来进行序列化。
有时候我们已经在自己的.NET项目里创建了一些模型,但我们需要使用Protobuf对这些模型进行序列化。
这时候这个库就能帮助你使用Protobuf对已存在的模型进行序列化。
Github地址:Wodsoft.Protobuf.Wrapper
Wodsoft.Protobuf.Wrapper需要NETStandard 2.0或以上。
这个库需要工作在允许动态代码编译的平台。所以IOS不支持。
在NuGet上获取Wodsoft.Protobuf.Wrapper.
可以使用<code>Wodsoft.Protobuf.Message</code>类中的静态方法<code>Serialize</code>。
你需要一个<code>System.IO.Stream</code>来存储序列化后的数据。
这里也有一个重载方法。
你可以传递一个<code>Google.Protobuf.CodedInputStream</code>来替代<code>System.IO.Stream</code>。
或者你想直接拿到序列化后的字节数组。
你可以使用<code>Wodsoft.Protobuf.Message</code>类中的静态方法<code>Deserialize</code>。
你需要传递包含需要反序列化数据的<code>System.IO.Stream</code>。
它将返回你的泛型对象<code>T</code>。
你可以传递一个<code>Google.Protobuf.CodedOutputStream</code>来替代<code>System.IO.Stream</code>。
或者你想直接从字节数组进行反序列化。
<code>IMessageFieldProvider.GetFields(Type type)</code>会返回从对象映射而来的消息字段。
默认实现是<code>GeneralMessageFieldProvider.Intance</code>类。
它只会映射可读写的属性到消息字段。
你可以创建自己的<code>IMessageFieldProvider</code>去映射消息字段。
然后通过设置静态属性<code>Message<T>.FieldProvider</code>为自定义的<code>IMessageFieldProvider</code>。
你需要为每个需要自定义消息字段的类型设置<code>IMessageFieldProvider</code>。
给属性添加<code>System.Runtime.Serialization.DataMemberAttribute</code>特性然后设置<code>Order</code>属性。
不然将根据属性名称进行排序。
⚠️ 如果有任何一个属性使用了<code>DataMemberAttribute</code>特性,将只会序列化拥有<code>DataMemberAttribute</code>特性的属性。
⚠️ 如果全部没有使用<code>DataMemberAttribute</code>特性,服务如果因为部署问题使用了不同版本的模型,反序列化时可能因为字段排序问题存在错误。
通过调用静态方法<code>MessageBuilder.SetTypeInitializer<T>(Func<T> initializer)</code>来设置对象初始化委托。
我们可以直接转换模型对象为<code>Message<></code>。
然后这个<code>message</code>可以直接被Protobuf序列化。
C#类型
Protobuf类型
消息结构
bool(?)
bool
Varint
sbyte(?)
int32
byte(?)
short(?)
ushort(?)
int(?)
long(?)
int64
uint(?)
uint32
ulong(?)
uint64
float(?)
float
double(?)
double
string
Length-delimited
byte[]
ByteString
Guid(?)
DateTime(?)
google.protobuf.Timestamp
DateTimeOffset(?)
TimeSpan(?)
google.protobuf.Duration
IMessage
T[]
RepeatedField<T>
ICollection<T>
Collection<T>
IList<T>
List<T>
IDictionary<TKey, TValue>
MapField<TKey, TValue>
Dictionary<TKey, TValue>
(?) 意思是可以为<code>Nullable<></code>可空类型。
可以直接使用继承了<code>Google.Protobuf.IMessage</code>的Protobuf对象作为属性类型。
所有<code>RepeatedField</code>与<code>MapField</code>对象不能包含<code>null</code>值。
支持<code>byte</code>,<code>sbyte</code>,<code>short</code>和<code>ushort</code>作为属性类型。
它们将作为<code>int</code>类型进行序列化。
如果从其它第三方来源数据进行反序列化,<code>int</code>可能会丢失数据。
首先,Protobuf通过<code>Google.Protobuf.IMessage</code>与<code>Google.Protobuf.IBufferMessage</code>接口进行序列化工作。
我们定义了一个抽象类<code>Wodsoft.Protobuf.Message</code>。
然后定义抽象保护方法<code>Read</code>,<code>Write</code>,<code>CalculateSize</code>。
显式实现这些接口并调用这些方法。
然后定义泛型抽象类<code>Wodsoft.Protobuf.Message<T></code>。
这里有一个属性可以直接获取到原始类型值。然后我们实现了一些隐式转换操作。
最后,为需要序列化的类型动态创建继承了<code>Message<T></code>的类。
通过Emit动态创建代码实现<code>Read</code>,<code>Write</code>,<code>CalculateSize</code>方法。
建议使用 <code>RepeatedField<></code>,<code>IList<></code>或<code>ICollection<></code>作为集合属性的类型。
使用<code>RepeatedField<></code>会获得最佳性能(因为不需要额外类型转换)。
使用<code>IList<></code>或<code>ICollection<></code>在序列化时会转换为<code>RepeatedField<></code>。
使用<code>List<></code>或<code>Collection<></code>在序列化时会转换为<code>RepeatedField<></code>。
并且在反序列化时会转换回<code>List<></code>或<code>Collection<></code>(上一个会直接返回<code>RepeatedField<></code>)。
推荐使用 <code>MapField<,></code>或<code>IDictionary<,></code>作为字典属性的类型。
使用<code>MapField<,></code>会获得最佳性能。
使用<code>IDictionary<,></code>在序列化时会转换为<code>MapField<,></code>。
使用<code>Dictionary<,></code>在序列化时会转换为<code>MapField<,></code>。
并且在反序列化时会转换回<code>Dictionary<,></code>(上一个会直接返回<code>MapField<,></code>)。
库使用MIT许可证。