Net開源技術交流羣 976304396,禁止水,只能討論技術, 歡迎與我討論和性能相關的技術話題!
另外,我還在抖音申請了一個帳號,用來記錄本身的平常生活, 想了解我日常是怎麼寫代碼的嗎? 來關注我一下,哈哈! 抖音號: 198152455
Bssom.Net項目地址: https://github.com/1996v/Bssom.Net
Bssom協議地址: https://github.com/1996v/Bssomhtml
Bssom.Net是一個使用bssom結構協議實現的高性能結構化二進制序列化器,它具備如下特色,小巧,快速,功能性強.git
目前c#已經有不少二進制序列化器, 但這些序列化器都只提供了單一的序列化和反序列化功能.github
Bssom.Net採起了Bssom協議, 使序列化後的數據具備結構化特性, 且擁有直接對字段進行編組的功能, 這使得Bssom.Net能作到其它序列化器所達不到的事情.算法
Bssom(Binary search algorithm structure model object binary marshalling)是一個使用二分查找算法模型對對象進行結構化編組的協議,被編組後的數據具備特殊的元數據信息,根據這些元數據信息能夠高效的僅讀取和更改對象中的某個元素,這樣能夠在對大對象進行序列化和反序列化的過程當中沒必要由於只讀取或只寫入一個字段而形成完整的序列化開銷。數據庫
這裏是與.NET平臺下很是優秀的兩款序列化程序(MessagePack 和 Protobuf-net)進行性能比較的基準.編程
柱狀數據表明執行相同任務所花費的時間, 越低表明性能越快, 折線數據表明執行相同任務所產生的GC, 越低表明在執行中所產生的垃圾越少 , 從性能比較結果能夠看出Bssom.Net的性能是很是優異的.c#
Bssom.Net使用不少技術來提升性能.api
System.Memory.dll
, 所以沒法使用Span<T>
,Memory<T>
等類型, 這意味着Bssom.Net的實現將沒法使用ByReference<T>
這一JIT內部特性, 所以目前的讀寫器將不具有讀寫局部化和去虛擬化及內聯調用的這三個性能優化點 ( 但即便這樣, 目前的Bssom.Net性能依然很是優秀 ) , 若未來有可能支持Span<T>
類型的話, 那麼Bssom.Net將會經過一些額外的性能技巧來再次提高性能.Bssom.Net對於讀取和寫入的入口並非直接使用原生的Byte[]
, 而是提供了緩衝區接口IBssomBuffer
和寫入器接口IBssomBufferWriter
.
與原生的byte[]
不一樣, 接口將更加靈活, 實現IBssomBuffer
後能夠從任意來源來讀取數據, 實現IBssomBufferWriter
後能夠將數據寫在任意地方(好比非連續的片斷)數組
IBssomBuffer
是一個用於序列化的緩衝區接口, 提供了讀取的行爲.緩存
方法 | 描述 |
---|---|
Position | 緩衝區中的當前位置 |
ReadRef | 從當前緩衝區中的位置讀取指定大小序列的引用 |
Seek | 設置當前緩衝區的位置 |
SeekWithOutVerify | 設置當前緩衝區的位置, 而且不對position的邊界進行驗證 |
TryReadFixedRef | 嘗試從當前緩衝區中的位置讀取一個能夠固定的字節序列的引用, 當進行Seek操做的時候不會影響被固定字節的引用位置 |
UnFixed | 用於取消由TryReadFixedRef所固定的引用, 此方法的調用始終和TryReadFixedRef對稱 |
IBssomBufferWriter
是基於緩衝區的寫入接口, 提供了寫入行爲
方法 | 描述 |
---|---|
Buffered | 在緩衝區中已寫入字節的數目 |
Advance | 用於指示已寫入緩衝區的部分 |
Position | 寫入器的當前位置 |
Seek | 設置當前寫入器的位置 |
SeekWithOutVerify | 設置當前寫入器的位置, 而且不對Buffered的邊界進行驗證 |
GetRef | 從當前位置獲取用於寫入的字節序列的引用 |
CanGetSizeRefForProvidePerformanceInTryWrite | 在字段編組中, 當前位置是否能提供指定大小的字節序列引用以用來提供內部某些類型寫入的性能 |
GetBssomBuffer | 獲取當前寫入器所使用的緩衝區 |
Bssom.Net內部已經對byte[]
, Stream
進行了IBssomBuffer
和IBssomBufferWriter
接口的封裝, 用戶無需手動封裝
格式化是Bssom.Net將.Net對象和Bssom格式進行互相轉換的一個過程. Bssom.Net經過IBssomFormatter<T>
來實現對對象的格式化.
API | 描述 |
---|---|
Size | 獲取對象被序列化後的大小 |
Serialize | 將對象序列化成Bssom二進制格式 |
Deserialize | 將Bssom二進制格式反序列化成對象 |
Bssom.Net內部已經內置了許多格式化器, 如.NET的基元類型, 鍵值對類型, 可迭代類型... 他們在Bssom.Serializer.Formatters
命名空間下, 你能夠找到它並直接調用它.
若是你不須要特殊的處理某個類型的話, 那麼這些格式化器基本能夠覆蓋你的大部分需求. 而如何找到格式化器, 這則是解析器所須要作的.
解析是將.Net類型對象獲取到對應的格式化器的一個過程.Bssom.Net經過IFormatterResolver
來實現對對象的解析.
API | 描述 |
---|---|
GetFormatter | 獲取對象的格式化器實例 |
解析器一般具有解析類型和保存格式化器這兩種功能, Bssom.Net中已實現的解析器在內部會對.net類型進行格式化器的查找, 而後經過靜態泛型的特性緩存被找到的格式化器, 完成了將一個或一組.net類型綁定到對應的格式化器的這樣過程.
IFormatterResolver
是Bssom.NET開始對對象序列化的最上層的入口, 他們在Bssom.Serializer.Resolvers
命名空間下.
名稱 | 描述 |
---|---|
PrimitiveResolver | 該解析器提供了sbyte ,Int16 ,Int32 ,Int64 ,byte ,UInt16 ,UInt32 ,UInt64 ,Single ,Double ,bool ,char ,Guid ,Decimal ,string ,DateTime 的類型的解析器 |
AttributeFormatterResolver | 獲取並提供用戶自定義格式化器的實例 |
BuildInResolver | 提供了StringBuilder ,BitArray ,DataTable 等類型的解析器 |
BssomValueResolver | 提供了BssomValue 類型的解析器 |
IDictionaryResolver | 獲取和生成具備IDictionary 行爲的類型的解析器, 該解析器抽象了BCL中對於鍵值對定義的行爲規則, 爲知足該規則的對象進行動態解析代碼的生成.在解析器內部, 將經過運行時的配置選項來選擇Map1 或Map2 的兩種格式 |
ICollectionResolver | 獲取和生成具備IColloction 行爲的類型的解析器, 該解析器抽象了BCL中對於收集器定義的行爲規則, 爲知足該規則的對象進行動態解析代碼的生成. 在解析器內部, 若是集合中的元素類型爲基元類型, 則將其解析成Array1 格式, 不然解析爲Array2 格式 |
MapCodeGenResolver | 獲取和生成對象的公開字段和屬性進行BssomMap類型編碼的解析器, 若對象爲接口, 則會自動生成該接口的實現做爲反序列化的載體.在解析器內部, 始終將類型解析爲Map2 格式, 且提供Map1 和Map2 兩種格式的反序列化代碼 |
ObjectResolver | 提供了Object 類型的解析器 |
CompositedResolver | 複合解析器,組合了Object ,Primitive ,Attribute ,BssomValue ,BuildIn ,IDictionary ,ICollection ,MapCodeGen 解析器 |
由於
IDictionaryResolver
和ICollectionResolver
中定義的足夠抽象的規則,Bssom.Net不須要爲將來.NET可能出現的新的IDictionary
或IColloction
實現而編寫特定的解析代碼.
在Bssom.Net中能夠經過BssomSerializerOptions
中的FormatterResolver
屬性來注入序列化所須要的解析器, 默認爲CompositedResolver
, CompositedResolver
將會對類型依次從 Object
,Primitive
,Attribute
,BssomValue
,BuildIn
,IDictionary
,ICollection
,MapCodeGen
解析器中進行查找, 直到找到對應的解析器.
讓咱們看一下Bssom.Net序列化的過程:
input T -> Call serialize(T) -> Find BssomResolver -> Provide type formatter -> formatter.Serialize(T);
在整個序列化的過程當中, 每一個步驟都是透明的, 這意味着若用戶對Bssom.Net內部定義的解析器或格式化器不滿意的話, 則能夠本身擴展它.
用戶能夠本身經過實現IFormatterResolver
和IBssomFormatter
來替代默認的解析器, 在Bssom.Serializer.Binary.BssomBinaryPrimitives
(在即將到來的小版本中將重構該類)和讀寫器自己所暴露的公開API中提供對Bssom格式的低級寫入和讀取實現.
簡單示例能夠參考更多可能介紹
BssomSerializer
是Bssom最上層的API, 在Bssom.Serializer
命名空間下, 是Bssom開始工做的入口. 它的靜態方法構成了Bssom.Net的主要API.
API | 描述 | 重載 |
---|---|---|
Size | 在不進行序列化的狀況下, 獲取對象被序列化後的二進制數據大小 | (t, option),(ref context, t) |
Serialize | 將給定的值序列化爲Bssom二進制 | (byte[], t, option), (stream, t, option), (IBssomBufWriter, t, option), (ref context, t) |
Deserialize | 將Bssom二進制數據反序列化成.net對象 | (byte[], option),(stream, option),(IBssomBuf, option),(ref context) |
SerializeAsync | 異步的序列化給定的值爲Bssom二進制 | 同上 |
DeserializeAsync | 異步的將Bssom二進制數據反序列化成.net對象 | 同上 |
BssomSerializer
做爲最上層的API,咱們在調用它時,須要傳遞一個可空的BssomSerializerOptions
類型的Option參數.
BssomSerializerOptions
是Bssom在整個序列化工做期間所須要使用的配置. 默認爲BssomSerializerOptions.Default
.
FormatterResolver
註冊解析器, 若是沒有手動註冊, 則使用默認的CompositedResolver
, Bssom將老是經過FormatterResolver
來對類型進行解析.false
, 則默認反序列化爲原生類型. 默認爲false
.DateTime
類型實現了標準的Bssom協議Unix格式 和 .NET平臺的本地格式, 本地格式具備更少的字節, 但不具有和其它平臺的交互性, 默認爲false
.IDictionary
行爲的類型默認使用哪一種格式進行序列化, 若是爲true
則使用Map1
格式, 不然爲Map2
格式. 默認爲true
BssomSerializeContext
提供了序列化期間所使用的上下文信息, 這其中也包括了BssomSerializerOptions
Bssom.Net擁有讀取字段而不用徹底反序列化和更改值而不用徹底序列化功能, 這是由於Bssom協議有着良好的結構化特徵, 在Bssom.Net的實現裏, 這樣的功能則暴露在BssomFieldMarshaller
中.
BssomFieldMarshaller
提供一套API用於對被序列化後的數據進行更低粒度的控制.
API | 描述 |
---|---|
IndexOf | 經過特殊的輸入格式來獲取被指定的對象在Bssom二進制中的位置,返回偏移量信息 |
ReadValue | 經過指定的偏移量信息來讀取整個元素 |
ReadValueType | 經過指定的偏移量信息僅讀取元素類型 |
ReadValueTypeCode | 經過指定的偏移量信息僅讀取元素類型的二進制碼 |
ReadValueSize | 經過指定的偏移量信息來獲取元素在Bssom二進制中所存儲的大小 |
ReadArrayCountByMapType | 經過指定的偏移量信息來讀取BssomArray的元素數量 |
ReadAllKeysByMapType | 經過指定的偏移量信息來讀取BssomMap中的元數據(包含Key和值的偏移量) |
TryWrite | 經過指定的偏移量信息在Bssom二進制中從新對值進行寫入, 若寫入值的寬度大於被寫入槽的寬度,則失敗 |
每種方法都提供了 byte[]
和 IBssomBuf
的重載
Bssom.Net爲IndexOf
定義了一種簡單的字段訪問語言, 該語言共定義了兩種訪問形式, 一種是訪問Map
類型(該Map類型的鍵必須爲String
類型), 一種是訪問Array
類型. 兩種訪問形式能夠自由組合.
Key
來訪問Map
類型的值, 輸入的Key
只表示String
類型Array
類型的元素, 輸入的Index只能是整數類型假設有以下數據
{ "Postcodes" : { "WuHan" : [430070,430071,430072,430073], "XiangYang" : [441000,441001,441002] }, "Province" : "HuBei" }
能夠經過以下方式進行元素訪問, 在示例中能夠了解更多細節
[Postcodes][WuHan]$1 => 4330071 [Province] => "HuBei"
Bssom.Net爲IndexOf
提供了IIndexOfInputSource
接口用來接收自定義的字段訪問源, 使用該接口後Map類型的Key將再也不受限制, Key能夠爲任意輸入類型.
IndexOfObjectsInputSource
是 Bssom.Net爲用戶提供的IIndexOfInputSource
接口的通用實現. 它接收一組可迭代的對象,當調用IndexOf的時候, 將依次對對象進行迭代.
假設有以下數據
{ 2018-01-01 : { 0 : ["Rain1","Rain2","Rain3"], 4 : ["Rain4","Fair5","Fair6"] } }
能夠經過以下方式進行元素訪問, 在示例中能夠了解更多細節
new IndexOfObjectsInputSource(new Entry[]{ new Entry(DateTime.Parse("2018-01-01"),ValueIsMapKey: true), new Entry(3,ValueIsMapKey: true), new Entry(1,ValueIsMapKey: false), }) output => "Fair5"
Bssom.Net對IDictionaryResolver
, ICollectionResolver
, MapCodeGenResolver
, ObjectResolver
使用了動態代碼生成技術, 經過表達式樹和Emit共同生成運行時代碼, 若是應用程序是純AOT環境, 則將不支持.
在MapCodeGenResolver
中對Map1
類型的反序列化使用了以8字節(64位字長)爲單位的類前綴樹的自動機查找模式, 這是很是有效且快速的方式, 它避免了對字符串進行徹底Hash運算以及字符比較開銷, 經過對MapCodeGenResolver.Save()
方法你將看到這些自動生成的代碼.
MapCodeGenResolver
中對Map2
類型的反序列化則使用了內置的Bssom協議的Map格式查找代碼,該代碼是狀態機模式編寫, 分爲快速和低速版, 這取決於讀取器是否可以提供 TryReadFixedRef.
另外,對於Size
方法,MapCodeGenResolver的處理也是很是快速的,由於它已經提早計算好了元數據的大小,而且內聯了基元字段自己的固定大小.
Bssom.Net中目前擁有5個特性.
IgnoreKeyAttribute
做用相反,優先級更高你能夠本身編寫解析器, 編寫格式化器, 也能夠定義你本身的特性, 也能夠封裝用於序列化的Option, 而且Bssom.Net還提供了上下文數據槽的支持, 這可讓序列化行爲變得多樣性.
若是你能爲Bssom.Net提供有用或者側重於高性能的擴展包, 那麼請您告訴我.
下面示例編寫了以String類型爲原型的解析器, 該解析器經過與上下文交互的方式來帶來字符串類型序列化性能的提高.
public sealed class MyStringFormatterResolver : IFormatterResolver { public static MyStringFormatterResolver Instance = new MyStringFormatterResolver(); public IBssomFormatter<T> GetFormatter<T>() { return FormatterCache<T>.Formatter; } private static class FormatterCache<T> { public static readonly IBssomFormatter<T> Formatter; static FormatterCache() { if (typeof(T) == typeof(string)) Formatter = (IBssomFormatter<T>)(object)MyStringFormatter.Instance; } } }
public sealed class MyStringFormatter : IBssomFormatter<string> { public static MyStringFormatter Instance = new MyStringFormatter(); public string Deserialize(ref BssomReader reader, ref BssomDeserializeContext context) { if (reader.TryReadNull()) { return null; } reader.EnsureType(BssomType.StringCode); int dataLen = reader.ReadVariableNumber(); ref byte refb = ref reader.BssomBuffer.ReadRef((int)dataLen); fixed (byte* pRefb = &refb) { return new string((sbyte*)pRefb, 0, (int)dataLen, UTF8Encoding.UTF8); } } public void Serialize(ref BssomWriter writer, ref BssomSerializeContext context, string value) { if (value == null) { writer.WriteNull(); return; } int valueUtf8Size = context.ContextDataSlots.PopMyStringSize(); writer.WriteBuildInType(BssomType.StringCode); writer.WriteVariableNumber(valueUtf8Size); ref byte refb = ref writer.BufferWriter.GetRef(valueUtf8Size); fixed (char* pValue = value) fixed (byte* pRefb = &refb) { UTF8Encoding.UTF8.GetBytes(pValue, value.Length, pRefb, valueUtf8Size); } writer.BufferWriter.Advance(valueUtf8Size); } public int Size(ref BssomSizeContext context, string value) { if (value == null) return BssomBinaryPrimitives.NullSize; int dataSize = UTF8Encoding.UTF8.GetByteCount(value); context.ContextDataSlots.PushMyStringSize(dataSize); return BssomBinaryPrimitives.BuildInTypeCodeSize + dataSize; } }
public void MyTest() { var option = BssomSerializerOptions.Default.WithFormatterResolver(MyStringFormatterResolver.Instance); string str = RandomHelper.RandomValue<string>(); BssomSizeContext sizeContext = new BssomSizeContext(option); int len = BssomSerializer.Size(ref sizeContext, str); if (len > 1000) throw new Exception("Size of value storage binary exceeded"); BssomSerializeContext serContext = new BssomSerializeContext(option); sizeContext.ContextDataSlots.SetMyStringStack(serContext.ContextDataSlots); var bytes = BssomSerializer.Serialize(ref serContext, str); var deStr = BssomSerializer.Deserialize<string>(bytes); Assert.Equal(str,deStr); }
上面的代碼是單獨爲String定義了一個新的解析器和新的格式化器, 該格式化器能夠將Size方法中對字符串計算的UTF8大小存儲在上下文中, 這樣在序列化時不用重複對String再作一次UTF8大小計算.
Bssom.Net是無合約的, 開箱即用, 這裏有些示例代碼.
BssomSerializer.Size 方法用於 獲取對象被序列化後的二進制數據大小,高性能的內部實現,幾乎無開銷
//獲取值被序列化後的大小 object value = RandomHelper.RandomValue<object>(); int size = BssomSerializer.Size(value, option: BssomSerializerOptions.Default);
//使用上下文獲取值被序列化後的大小 BssomSizeContext context = new BssomSizeContext(BssomSerializerOptions.Default); object value = RandomHelper.RandomValue<object>(); int size = BssomSerializer.Size(ref context, value);
BssomSerializer.Serialize 方法用於 將給定的值序列化爲Bssom二進制,高性能的內部實現,如下是部分經常使用方法,每一個方法都擁有CancellationToken的重載
//直接對對象進行序列化,將返回一個被序列化後的字節數組 object value = RandomHelper.RandomValue<object>(); byte[] binary = BssomSerializer.Serialize(value, option: BssomSerializerOptions.Default);
//將對象序列化到指定的字節數組中,若容量不夠將自動擴容,最終返回序列化的字節數 object value = RandomHelper.RandomValue<object>(); byte[] buf = local(); int serializeSize = BssomSerializer.Serialize(ref buf, 0, value, option: BssomSerializerOptions.Default);
//將對象序列化到自定義的寫入器中 object value = RandomHelper.RandomValue<object>(); IBssomBufferWriter writer = new Impl(); BssomSerializer.Serialize(value, writer, option: BssomSerializerOptions.Default);
//使用序列化上下文進行序列化 object value = RandomHelper.RandomValue<object>(); BssomSerializeContext context = new BssomSerializeContext(BssomSerializerOptions.Default); byte[] binary = BssomSerializer.Serialize(ref context, value);
//將對象序列化到流中 object value = RandomHelper.RandomValue<object>(); Stream stream = new MemoryStream(); BssomSerializer.Serialize(stream, value, option: BssomSerializerOptions.Default);
//異步的將對象序列化到流中 object value = RandomHelper.RandomValue<object>(); Stream stream = new MemoryStream(); await BssomSerializer.SerializeAsync(stream, value, option: BssomSerializerOptions.Default);
BssomSerializer.Deserialize 方法用於 將給定的Bssom緩衝區反序列化爲對象,高性能的內部實現,如下是部分經常使用方法,每一個方法都擁有CancellationToken的重載
//從給定的字節數組中反序列化對象 byte[] buf = remote(); T value = BssomSerializer.Deserialize<T>(buf, 0, out int readSize, option: BssomSerializerOptions.Default);
//從給定的buffer中反序列化對象 IBssomBuffer buffer = remote(); object value = BssomSerializer.Deserialize<object>(buffer, option: BssomSerializerOptions.Default);
//使用上下文從給定的buffer中反序列化對象 BssomDeserializeContext context = new BssomDeserializeContext(BssomSerializerOptions.Default); IBssomBuffer buffer = remote(); object value = BssomSerializer.Deserialize<object>(ref context, buffer);
//從流中反序列化對象 Stream stream = remote(); object value = BssomSerializer.Deserialize<object>(stream, option: BssomSerializerOptions.Default);
//異步的從流中反序列化對象 Stream stream = remote(); object value = await BssomSerializer.DeserializeAsync<object>(stream, option: BssomSerializerOptions.Default);
//傳遞一個Type, 從流中反序列化對象爲指定的Type類型 Stream stream = remote(); Type type = typeof(class); object value = BssomSerializer.Deserialize(stream, type, option: BssomSerializerOptions.Default);
//傳遞一個Type, 異步的從流中反序列化對象爲指定的Type類型 Stream stream = remote(); Type type = typeof(class); object value = await BssomSerializer.DeserializeAsync(stream, type, option: BssomSerializerOptions.Default);
BssomFieldMarshaller.ReadValue 方法用於 在二進制數據中僅讀取某一個值,若是你只想讀取對象中的某一個值,而不用完整的反序列化它,那麼這個方法很是有用
//經過內嵌的簡單字段訪問語言,獲取Dict中的一個Key對應的值 var val = new Dictionary<string, object>() { { "A",(int)3}, { "B",(DateTime)DateTime.MaxValue}, }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); BssomFieldOffsetInfo fieldOffInfo = bsfm.IndexOf("[A]") bsfm.ReadValue<int>(fieldOffInfo).Is(3);
//經過內嵌的簡單字段訪問語言,獲取class中的一個屬性的值 var val = new MyClass() { Name = "bssom", Nature = "Binary" }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); BssomFieldOffsetInfo fieldOffInfo = bsfm.IndexOf("[Name]") bsfm.ReadValue<string>(fieldOffInfo).Is("bssom");
//經過內嵌的簡單字段訪問語言,獲取數組中的一個屬性的值 var val = new object[] { (int)1,(double)2.2 } var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); BssomFieldOffsetInfo fieldOffInfo = bsfm.IndexOf("$1") bsfm.ReadValue<double>(fieldOffInfo).Is((double)2.2);
//經過內嵌的簡單字段訪問語言,組合獲取一個對象 var val = new MyClass() { Name = "bssom", Nature = "Binary", Data = new int[] { 3, 2, 1} }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); BssomFieldOffsetInfo fieldOffInfo = bsfm.IndexOf("[Data]$1") bsfm.ReadValue<int>(fieldOffInfo).Is(2);
//經過自定義的字段訪問形式,組合獲取一個對象 var val = new Dictionary<object, object>() { { DateTime.Parse("2018-01-01"), new object[]{'A','B'} }, { "Charec",(DateTime)DateTime.MaxValue}, }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); IIndexOfInputSource input = new IndexOfObjectsInputSource(new Entry[]{ new Entry(DateTime.Parse("2018-01-01"),ValueIsMapKey: true), new Entry(1,ValueIsMapKey: false), }) BssomFieldOffsetInfo fieldOffInfo = bsfm.IndexOf(input) bsfm.ReadValue<int>(fieldOffInfo).Is('B');
BssomFieldMarshaller.ReadAllMapKeys 方法用於 在二進制數據中讀取Map格式的全部Key和值偏移量,若是你想了解該二進制數據中的鍵值狀況,但又不想徹底讀取它,那麼這個方法很是有用.
var val = new Dictionary<object, object>(){ { "Id" , 1 }, { "Path" , "../t.jpg" }, { "Data" , new byte[3000] } }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); bsfm.ReadAllMapKeys<object>(BssomFieldOffsetInfo.Zero).Print(); //output // line 1: BssomString::"Id", BssomFieldOffsetInfo // line 2: BssomString::"Path", BssomFieldOffsetInfo // line 3: BssomString::"Data", BssomFieldOffsetInfo
BssomFieldMarshaller.TryWriteValue 方法用於 對二進制數據的值進行修改,當你只想修改對象中的某個值,而不用從新序列化整個對象時,那麼這個方法很是有用
//修改字符串對象 var val = "abcd"; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); bsfm.TryWrite(BssomFieldOffsetInfo.Zero, "abc"); string upVal = BssomSerializer.Deserialize<string>(buf); upVal.Is("abc");
//修改IDict對象中的某個鍵 var val = new Dictionary<string, object>(){ { "Id" , 1 }, { "Path" , "../t.jpg" }, { "Data" , new byte[3000] } }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); bsfm.TryWrite(bsfm.IndexOf("[Id]"), 3); var upVal = BssomSerializer.Deserialize<Dictionary<string, object>>(buf); upVal["Id"].Is(3);
//修改IDict對象中的某個鍵 var val = new MyClass() { Name = "bssom", Nature = "Binary", Data = new int[] { 3, 2, 1} }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); bsfm.TryWrite(bsfm.IndexOf("[Name]"), "zz"); var upVal = BssomSerializer.Deserialize<MyClass>(buf); upVal["Name"].Is("zz");
//修改Array對象中的某個元素 var val = new object[] { "abc" , 37 }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); bsfm.TryWrite(bsfm.IndexOf("$1"), 40); var upVal = BssomSerializer.Deserialize<MyClass>(buf); ((int)upVal[1]).Is(40);
//組合修改對象中的某個元素 var val = new object[] { 22, 37, new MyClass() { Name = "bssom", Nature = "Binary", Data = new int[] { 3, 2, 1} } }; var buf = BssomSerializer.Serialize(val); var bsfm = new BssomFieldMarshaller(buf); bsfm.TryWrite(bsfm.IndexOf("$2[Name]"), "zz"); var upVal = BssomSerializer.Deserialize<MyClass>(buf); ((MyClass)upVal[1]).Name.Is("zz");
我喜歡和我同樣的人交朋友,不被環境影響,本身是本身的老師,歡迎加羣 Net開源技術交流羣 976304396 ,與我討論與性能相關的話題!
想了解我平常是怎樣寫代碼的嗎? 歡迎關注個人抖音帳號: 198152455 .
做者:小曾
出處:http://www.javashuo.com/article/p-rtejcbun-nu.html 歡迎轉載,但請保留以上完整文章,在顯要地方顯示署名以及原文連接。 Net開源技術交流羣 976304396 , 抖音帳號: 198152455