• C#的MessagePack(unity)--02


    高级API (MessagePackSerializer)

    MessagePackSerializer类是MessagePack for C# 的入口点。静态方法构成了MessagePack for C# 的主要API。

    APIDescription
    Serialize将一个对象图序列化为MessagePack二进制块。可以使用异步变体获取Stream。也有非泛型重载可用。
    Deserialize将MessagePack二进制转换为对象图。可用于Stream的异步变体。也有非泛型重载可用。
    SerializeToJson将MessagePack兼容的对象图序列化为JSON,而不是MessagePack。这对调试很有帮助。
    ConvertToJson将MessagePack二进制转换为JSON。这对调试很有帮助
    ConvertFromJson将JSON转换为MessagePack二进制。

    MessagePack for C#基本上使用IBufferWriter 进行序列化,并使用ReadOnlySequence 或Memory 进行反序列化。提供了方便的方法重载来方便地与常见的缓冲区类型和.NET Stream 类配合使用,但这些便捷重载需要复制缓冲区一次,因此有一定的开销。

    高级API内部使用内存池来避免不必要的内存分配。如果结果大小小于64K,则只为返回字节分配GC内存。

    每个serialize / deserialize方法都可选地接受一个MessagePackSerializerOptions参数,可用于指定要使用的自定义IFormatterResolver或激活LZ4压缩支持。

    单个Stream上的多个MessagePack结构

    要反序列化包含多个连续MessagePack数据结构的流,您可以使用MessagePackStreamReader类来高效地识别每个数据结构的ReadOnlySequence 并对其进行反序列化。例如:

    1. static async Task<List<T>> DeserializeListFromStreamAsync<T>(Stream stream, CancellationToken cancellationToken)
    2. {
    3. var dataStructures = new List();
    4. using (var streamReader = new MessagePackStreamReader(stream))
    5. {
    6. while (await streamReader.ReadAsync(cancellationToken) is ReadOnlySequence<byte> msgpack)
    7. {
    8. dataStructures.Add(MessagePackSerializer.Deserialize(msgpack, cancellationToken: cancellationToken));
    9. }
    10. }
    11. return dataStructures;
    12. }

    低级API (IMessagePackFormatter)

    IMessagePackFormatter 接口负责序列化一个唯一的类型。例如,Int32Formatter : IMessagePackFormatter表示Int32 MessagePack 序列化器

    1. public interface IMessagePackFormatter<T>
    2. {
    3. void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options);
    4. T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options);
    5. }

    有许多内置格式器位于MessagePack.Formatters下。你的自定义类型通常会自动得到支持,并使用动态代码生成来生成新IMessagePackFormatter类型的内置类型解析器。对于不支持此功能的平台,请参阅我们的AOT代码生成支持。

    然而,一些类型(特别是由第三方库或运行时本身提供的类型)无法适当地注解,无合同序列化会产生效率低下甚至错误的结果。为了更好地控制此类自定义类型的序列化,编写您自己的IMessagePackFormatter实现。下面是一个这样的自定义格式器实现的例子。请注意它使用的原始API,该API在下一节中描述。

    1. /// <summary>Serializes a <see cref="FileInfo" /> by its full path as a string.</summary>
    2. public class FileInfoFormatter : IMessagePackFormatter<FileInfo>
    3. {
    4. public void Serialize(
    5. ref MessagePackWriter writer, FileInfo value, MessagePackSerializerOptions options)
    6. {
    7. if (value == null)
    8. {
    9. writer.WriteNil();
    10. return;
    11. }
    12. writer.WriteString(value.FullName);
    13. }
    14. public FileInfo Deserialize(
    15. ref MessagePackReader reader, MessagePackSerializerOptions options)
    16. {
    17. if (reader.TryReadNil())
    18. {
    19. return null;
    20. }
    21. options.Security.DepthStep(ref reader);
    22. var path = reader.ReadString();
    23. reader.Depth--;
    24. return new FileInfo(path);
    25. }
    26. }

    DepthStep 和 Depth--语句提供了一层安全保护,在反序列化不受信任的数据时,可能会导致拒绝服务攻击,发送会导致堆栈溢出异常的消息包数据,并崩溃进程。这两个语句应该包围任何IMessagePackFormatter.Deserialize 方法的主要部分。

    注意:一个message pack 格式器必须读写一个数据结构。在上述例子中我们只是读取或写入一个字符串。如果你有多个元素要写入,必须在前面加上map或array头。在反序列化时必须读取整个map/array。例如:

    1. public class MySpecialObjectFormatter : IMessagePackFormatter<MySpecialObject>
    2. {
    3. public void Serialize(
    4. ref MessagePackWriter writer, MySpecialObject value, MessagePackSerializerOptions options)
    5. {
    6. if (value == null)
    7. {
    8. writer.WriteNil();
    9. return;
    10. }
    11. writer.WriteArrayHeader(2);
    12. writer.WriteString(value.FullName);
    13. writer.WriteString(value.Age);
    14. }
    15. public MySpecialObject Deserialize(
    16. ref MessagePackReader reader, MessagePackSerializerOptions options)
    17. {
    18. if (reader.TryReadNil())
    19. {
    20. return null;
    21. }
    22. options.Security.DepthStep(ref reader);
    23. string fullName = null;
    24. int age = 0;
    25. // Loop over *all* array elements independently of how many we expect,
    26. // since if we're serializing an older/newer version of this object it might
    27. // vary in number of elements that were serialized, but the contract of the formatter
    28. // is that exactly one data structure must be read, regardless.
    29. // Alternatively, we could check that the size of the array/map is what we expect
    30. // and throw if it is not.
    31. int count = reader.ReadArrayHeader();
    32. for (int i = 0; i < count; i++)
    33. {
    34. switch (i)
    35. {
    36. case 0:
    37. fullName = reader.ReadString();
    38. break;
    39. case 1:
    40. age = reader.ReadInt32();
    41. break;
    42. default:
    43. reader.Skip();
    44. break;
    45. }
    46. }
    47. reader.Depth--;
    48. return new MySpecialObject(fullName, age);
    49. }
    50. }

    unity 支持

    Unity最低支持版本为2018.3,API 兼容级别同时支持.NET 4.x 和.NET Standard 2.0。

    可以从Release 页面安装unitypackage。如果构建目标是.NET Framework 4.x 并在mono上运行,可以直接使用它。但如果构建目标是IL2CPP,则不能使用Dynamic***Resolver,因此需要使用预代码生成。请参阅预代码生成部分。

    MessagePack for C# 包含一些NuGet中原先提供的额外System.*.dll库。它们位于Plugins文件夹下。如果其他包使用这些库(例如使用System.Runtime.CompilerServices.Unsafe.dll的Unity Collections包),为了避免冲突,请删除Plugins下的DLL。

    目前CompositeResolver.Create在IL2Cpp上不起作用,因此建议使用StaticCompositeResolver.Instance.Register。

    在Unity中,MessagePackSerializer可以使用内置扩展UnityResolver将Vector2、Vector3、Vector4、Quaternion、Color、Bounds、Rect、AnimationCurve、Keyframe、Matrix4x4、Gradient、Color32、RectOffset、LayerMask、Vector2Int、Vector3Int、RangeInt、RectInt、BoundsInt及其可空、数组和列表类型序列化。它默认包含在StandardResolver中。

    MessagePack for C# 还有一个额外的不安全扩展。UnsafeBlitResolver 是一个特殊解析器,用于结构数组的极高但不安全的序列化/反序列化

  • 相关阅读:
    Java(100):Java操作ES增删查(RestHighLevelClient)
    了解一下Monorepo
    react-antD 下拉框组件使用出现的问题(antd版本问题)-menus
    Go语学习笔记 - gorm使用 - 表增删改查 | Web框架Gin(八)
    word2016 电子签名
    不会DRF?源码都分析透了确定不来看?
    解决:vscode和jupyter远程连接无法创建、删除文件的问题(permission denied)
    HNU-CSer的推免经历记录
    Redis 7 第七讲 哨兵模式(sentinal)架构篇
    尚品汇后台管理项目(Vue)
  • 原文地址:https://blog.csdn.net/Edision_li/article/details/134462141