關于
需求
安裝
用法
序列化
反序列化
字段定義
字段排序
非空構造函數對象
擷取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許可證。