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