.NET性能优化-是时候换个序列化协议了( 二 )

命名空间,访问它的静态方法即可完成序列化和反序列化 。
using System.Text.Json;var obj = ....;// Serializevar json = JsonSerializer.Serialize(obj);// Deserializevar newObj = JsonSerializer.Deserialize<T>(json)Google Protobuf.NET上最常用的一个Protobuf序列化框架,它其实是一个工具包,通过工具包+*.proto文件可以生成GRPC Service或者对应实体的序列化代码,不过它使用起来有点麻烦 。
使用它我们需要两个Nuget包,如下所示:
<!--Google.Protobuf 序列化和反序列化帮助类--><PackageReference Include="Google.Protobuf" Version="3.21.9" /><!--Grpc.Tools 用于生成protobuf的序列化反序列化类 和 GRPC服务--><PackageReference Include="Grpc.Tools" Version="2.50.0"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference>由于它不能直接使用C#对象,所以我们还需要创建一个*.proto文件,布局和上面的C#类一致,加入了一个DemoClassArrayProto方便后面测试:
syntax="proto3";option csharp_namespace="DemoClassProto";package DemoClassProto;message DemoClassArrayProto{repeated DemoClassProto DemoClass = 1;}message DemoClassProto{int32 P1=1;bool P2=2;string P3=3;double P4=4;int64 P5=5;repeated DemoSubClassProto Subs=6;}message DemoSubClassProto{int32 P1=1;bool P2=2;string P3=3;double P4=4;int64 P5=5;}做完这一些后,还需要在项目文件中加入如下的配置,让Grpc.Tools在编译时生成对应的C#类:
<ItemGroup><Protobuf Include="*.proto" GrpcServices="Server" /></ItemGroup>然后Build当前项目的话就会在obj目录生成C#类:

.NET性能优化-是时候换个序列化协议了

文章插图
.NET性能优化-是时候换个序列化协议了

文章插图
最后我们可以用下面的方法来实现序列化和反序列化,泛型类型T是需要继承IMessage<T>*.proto生成的实体(用起来还是挺麻烦的):
using Google.Protobuf;// Serialize[MethodImpl(MethodImplOptions.AggressiveInlining)]public static byte[] GoogleProtobufSerialize<T>(T origin) where T : IMessage<T>{return origin.ToByteArray();}// Deserialize[MethodImpl(MethodImplOptions.AggressiveInlining)]public DemoClassArrayProto GoogleProtobufDeserialize(byte[] bytes){return DemoClassArrayProto.Parser.ParseFrom(bytes);}Protobuf.Net那么在.NET平台protobuf有没有更简单的使用方式呢?答案当然是有的,我们只需要依赖下面的Nuget包:
<PackageReference Include="protobuf-net" Version="3.1.22" />然后给我们需要进行序列化的C#类打上ProtoContract特性,另外将所需要序列化的属性打上ProtoMember特性,如下所示:
[ProtoContract]public class DemoClass{[ProtoMember(1)] public int P1 { get; set; }[ProtoMember(2)] public bool P2 { get; set; }[ProtoMember(3)] public string P3 { get; set; } = null!;[ProtoMember(4)] public double P4 { get; set; }[ProtoMember(5)] public long P5 { get; set; }}然后就可以直接使用框架提供的静态类进行序列化和反序列化,遗憾的是它没有提供直接返回byte[]的方法,不得不使用一个MemoryStrem
using ProtoBuf;// Serialize[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void ProtoBufDotNet<T>(T origin, Stream stream){Serializer.Serialize(stream, origin);}// Deserializepublic T ProtobufDotNet(byte[] bytes){using var stream = new MemoryStream(bytes);return Serializer.Deserialize<T>(stream);}MessagePack这里我们使用的是Yoshifumi Kawai实现的

经验总结扩展阅读