当前位置: 首页 > news >正文

DeepSeek教unity------MessagePack-06

无类型 Typeless

无类型的 API 类似于 BinaryFormatter,因为它会将类型信息嵌入到数据块中,所以在调用 API 时不需要显式指定类型。

MessagePackSerializer.Typeless 是 Serialize/Deserialize<object>(TypelessContractlessStandardResolver.Instance) 的快捷方式。如果你想将其配置为默认解析器,可以使用 MessagePackSerializer.Typeless.RegisterDefaultResolver

TypelessFormatter 可以单独使用或与其他解析器组合使用。

/****************************************************
    文件:Test_07.cs
	作者:Edision
    日期:#CreateTime#
	功能:示例7:typeless
*****************************************************/

using MessagePack;
using MessagePack.Formatters;
using UnityEngine;

public class Test_07 : MonoBehaviour
{
    object mc = new MyClass()
    {
        Age = 10,
        FirstName = "hoge",
        LastName = "huga"
    };

    public void Test()
    {
        // Serialize with the typeless API
        var bin = MessagePackSerializer.Typeless.Serialize(mc);

        // 数据块中嵌入了类型-程序集信息。
        // ["MyClass, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",10,"hoge","huga"]
        Debug.Log(MessagePackSerializer.ConvertToJson(bin));

        // 你可以使用无类型的 API 再次反序列化为 MyClass
        // 请注意,在反序列化调用中不需要显式指定类型
        // 因为类型信息已嵌入到二进制数据块中
        var objModel = MessagePackSerializer.Typeless.Deserialize(bin) as MyClass;
        Debug.Log(objModel);

        //

        // Replaced `object` uses the typeless resolver
        var resolver = MessagePack.Resolvers.CompositeResolver.Create(
            new[] { TypelessFormatter.Instance },
            new[] { MessagePack.Resolvers.StandardResolver.Instance });

        //如果类型名称后来被更改,你将无法再反序列化旧的数据块。
        //但是在这种情况下,你可以通过提供自己的 TypelessFormatter.BindToType 函数指定一个回退名称。

        MessagePack.Formatters.TypelessFormatter.BindToType = typeName =>
        {
            if (typeName.StartsWith("SomeNamespace"))
            {
                typeName = typeName.Replace("SomeNamespace", "AnotherNamespace");
            }

            return Type.GetType(typeName, false);
        };
    }
}

[MessagePackObject]
public class MyClass
{
    [Key(0)]
    public int Age { get; set; }

    [Key(1)]
    public string FirstName { get; set; }

    [Key(2)]
    public string LastName { get; set; }

    // 所有不应被序列化的字段或属性必须用 [IgnoreMember] 进行注解。
    [IgnoreMember]
    public string FullName { get { return FirstName + LastName; } }
}



public class Foo
{
    // use Typeless(this field only)
    [MessagePackFormatter(typeof(TypelessFormatter))]
    public object Bar;
}

从不受信任的来源反序列化数据可能会给你的应用程序引入安全漏洞。根据反序列化过程中使用的设置,不受信任的数据可能能够执行任意代码或导致拒绝服务攻击。不受信任的数据可能来自网络上的不受信任源(例如任何和所有联网客户端),或者在通过未验证连接传输时被中间者篡改,也可能来自可能已被篡改的本地存储,或其他许多来源。MessagePack for C# 不提供任何验证数据或防止其被篡改的方法。请在反序列化之前使用适当的方法验证数据 - 例如 MAC(消息认证码)。

请注意这些攻击场景;过去,许多项目和公司以及序列化库用户都曾因不受信任的用户数据反序列化而遭受损失。

当反序列化不受信任的数据时,通过配置 MessagePackSerializerOptions.Security 属性将 MessagePack 设置为更安全的模式:

var options = MessagePackSerializerOptions.Standard
    .WithSecurity(MessagePackSecurity.UntrustedData);

// Pass the options explicitly for the greatest control.
T object = MessagePackSerializer.Deserialize<T>(data, options);

// Or set the security level as the default.
MessagePackSerializer.DefaultOptions = options;

MessagePack 是一种快速且紧凑的格式,但它不是压缩格式。LZ4 是一种极其快速的压缩算法,通过使用 LZ4,MessagePack for C# 可以实现极快的性能以及极其紧凑的二进制大小!

MessagePack for C# 内置了对 LZ4 的支持。你可以通过修改选项对象并将其传递给 API 来激活它,如下所示:

var lz4Options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray);
MessagePackSerializer.Serialize(obj, lz4Options);

MessagePack.Unity 在应用程序启动时自动将 UnityResolver 添加到默认选项解析器中,使用 unity 包中的代码启用此序列化功能,如下所示:

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void Init()
{
    MessagePackSerializer.DefaultOptions = MessagePackSerializerOptions.Standard.WithResolver(UnityResolver.InstanceWithStandardResolver);
}

以下是一些在使用 MessagePack for C# 时实现最大性能的建议:

1. 使用索引键

  • 使用索引键([Key(0)])而不是字符串键([Key("name")])可以显著提高序列化和反序列化的性能,因为索引键不需要处理和查找键名,且生成的二进制数据更紧凑。

  • 示例:

    [MessagePackObject]
    public class Person
    {
        [Key(0)]
        public string Name { get; set; }
        [Key(1)]
        public int Age { get; set; }
    }

2. 启用 LZ4 压缩

  • MessagePack for C# 内置了 LZ4 压缩支持,可以通过配置选项启用。LZ4 是一种快速的压缩算法,可以在不显著降低性能的情况下显著减小数据大小。

  • 示例:

    var options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray);
    byte[] binary = MessagePackSerializer.Serialize(obj, options);

3. 优化数据结构

  • 尽量使用简单的数据结构,避免嵌套过深的复杂结构,以减少序列化和反序列化的时间。

  • 如果需要处理大量数据,可以考虑批量处理,减少单次操作的开销。

4. 使用 IBufferWriter<byte>Stream API

  • 默认情况下,MessagePackSerializer.Serialize 返回 byte[],这会涉及额外的内存拷贝。使用 IBufferWriter<byte>Stream API 可以直接写入缓冲区,避免不必要的内存分配。

  • 示例:

    using var stream = new MemoryStream();
    MessagePackSerializer.Serialize(stream, obj, options);

5. 避免使用无合同解析器

  • 无合同解析器(Contractless)虽然方便,但会牺牲性能。如果性能是首要目标,建议显式使用 [MessagePackObject][Key] 特性。

6. 注意版本控制

  • 当类结构发生变化时,使用索引键时应保留废弃成员的索引,直到所有客户端都更新。

7. 调整压缩模式

  • 如果数据中存在大量重复内容,启用压缩可以显著减小数据大小。但需要注意,压缩效果因数据而异,建议根据实际数据测试压缩的实际效果。

通过以上优化,可以在使用 MessagePack for C# 时实现更高的性能和更紧凑的数据传输。

相关文章:

  • 【前端如何实现图片懒加载?】
  • Day65_20250213图论part9_dijkstra(堆优化版)|Bellman_ford算法精讲
  • HTTP 参数污染(HPP)详解
  • 开源大模型性能追平闭源模型技术路径分析
  • 1.初识SpringSecurity
  • VsCode美化 Json
  • 基于SSM+uniapp的租房小程序
  • React 中级教程
  • Linux线程概念与线程操作
  • soular基础教程-使用指南
  • nodejs版本管理,使用 nvm 删除node版本,要删除 Node.js 的某个版本详细操作
  • Java 大数据与区块链的融合:数据可信共享与溯源(45)
  • Spring Boot 整合 SSE(Server-Sent Events)
  • uniapp当页面高度设置100vh的时候。怎么让他禁止上下滚动
  • 尚硅谷爬虫note007
  • Ubuntu 上安装和配置 Nexus Repository Manager
  • React函数组件和类组件
  • DeepSeek的自动化能力如何
  • Ubuntu 24.04 上安装 Nginx
  • 【BUG】Ubuntu|有nvcc,没有nvidia-smi指令,找不到nvidia-driver安装包
  • 巴菲特股东大会前瞻:执掌伯克希尔60年,巨轮将驶向何方
  • 长三角铁路今日预计发送旅客420万人次,有望创单日客发量新高
  • 五一假期上海口岸出入境客流总量预计达59.4万人,同比增约30%
  • 八成盈利,2024年沪市主板公司实现净利润4.35万亿元
  • “五一”假期预计全社会跨区域人员流动量超14亿人次
  • 量子传感新技术“攻克”退相干难题