首页
/ MessagePack-CSharp在Unity IL2CPP环境下处理自定义类型序列化的解决方案

MessagePack-CSharp在Unity IL2CPP环境下处理自定义类型序列化的解决方案

2025-06-04 21:55:19作者:翟江哲Frasier

背景介绍

在使用MessagePack-CSharp进行Unity3D开发时,开发者可能会遇到一个常见问题:当项目使用IL2CPP编译后端时,包含自定义类型的对象数组无法正常序列化。这个问题在Mono环境下可能不会出现,但在IL2CPP环境下会抛出"Not supported primitive object resolver"异常。

问题分析

问题的核心在于MessagePack的PrimitiveObjectFormatter对于非基本类型(如int、bool、string等)的处理机制。在IL2CPP环境下,当尝试序列化一个包含自定义类型(如AirSimYawMode、AirSimPose等)的对象数组时,系统无法自动识别这些自定义类型,导致序列化失败。

解决方案

自定义解析器实现

要解决这个问题,我们需要创建一个自定义的解析器(CustomObjectArrayFormatter),专门用于处理对象数组的序列化和反序列化。这个解析器需要:

  1. 识别数组中的各种数据类型
  2. 为每种类型提供专门的序列化/反序列化逻辑
  3. 处理基本类型和自定义类型的不同情况
public class CustomObjectArrayFormatter : IMessagePackFormatter<object[]>
{
    public void Serialize(ref MessagePackWriter writer, object[] value, MessagePackSerializerOptions options)
    {
        writer.WriteArrayHeader(value.Length);
        foreach (var item in value)
        {
            switch (item)
            {
                case int intValue:
                    writer.Write(intValue);
                    break;
                case float floatValue:
                    writer.Write(floatValue);
                    break;
                case bool boolValue:
                    writer.Write(boolValue);
                    break;
                case string stringValue:
                    writer.Write(stringValue);
                    break;
                case AirSimYawMode yawMode:
                    options.Resolver.GetFormatterWithVerify<AirSimYawMode>().Serialize(ref writer, yawMode, options);
                    break;
                // 其他自定义类型处理...
                default:
                    throw new InvalidOperationException("Unsupported type encountered: " + item.GetType());
            }
        }
    }

    public object[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
    {
        var len = reader.ReadArrayHeader();
        var result = new object[len];
        for (int i = 0; i < len; i++)
        {
            var type = reader.NextMessagePackType;
            switch (type)
            {
                case MessagePackType.Integer:
                    result[i] = reader.ReadInt32();
                    break;
                case MessagePackType.Float:
                    result[i] = reader.ReadSingle();
                    break;
                case MessagePackType.Boolean:
                    result[i] = reader.ReadBoolean();
                    break;
                case MessagePackType.String:
                    result[i] = reader.ReadString();
                    break;
                default:
                    throw new InvalidOperationException("Unsupported MessagePackType encountered: " + type);
            }
        }
        return result;
    }
}

解析器注册

创建自定义解析器后,需要将其注册到MessagePack的解析器系统中。这通常在应用程序启动时完成:

var customize = CompositeResolver.Create(
    new IMessagePackFormatter[] { new CustomObjectArrayFormatter() },
    new[] { StandardResolver.Instance }
);

StaticCompositeResolver.Instance.Register(
    customize,
    MessagePack.Resolvers.StandardResolver.Instance,
    MessagePack.Resolvers.GeneratedResolver.Instance
);

实现细节说明

  1. 类型识别:在序列化过程中,使用C#的模式匹配功能(switch-case)来识别不同类型的值,并为每种类型提供专门的序列化逻辑。

  2. 自定义类型处理:对于自定义类型(如AirSimYawMode),通过options.Resolver获取对应的格式化器进行序列化。

  3. 数组处理:在序列化和反序列化时,首先处理数组头部信息(数组长度),然后逐个处理数组元素。

  4. 错误处理:遇到不支持的类型时抛出明确的异常信息,便于调试。

性能考虑

  1. 模式匹配优化:C#的模式匹配在性能上表现良好,但如果有大量不同类型的处理,可以考虑使用字典或其他查找结构来优化。

  2. 缓存格式化器:对于频繁使用的自定义类型格式化器,可以考虑缓存起来而不是每次都通过Resolver获取。

  3. 数组预分配:在反序列化时预先分配数组空间,避免频繁的内存分配。

扩展性设计

这个解决方案具有良好的扩展性:

  1. 添加新类型支持:只需在switch-case中添加新的类型处理分支即可支持新的自定义类型。

  2. 模块化设计:可以将不同类型的分支处理逻辑提取到单独的方法中,保持代码整洁。

  3. 条件编译:可以使用条件编译指令为不同平台提供特定的实现。

结论

通过实现自定义的对象数组解析器并正确注册到MessagePack系统中,我们可以有效解决IL2CPP环境下自定义类型序列化的问题。这种方法不仅解决了当前的问题,还提供了一个灵活、可扩展的框架,便于未来添加更多自定义类型的支持。对于Unity开发者来说,理解MessagePack的解析器机制并能够根据项目需求进行定制,是高效使用MessagePack-CSharp的关键技能之一。

登录后查看全文
热门项目推荐

项目优选

收起
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
178
262
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
867
513
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
129
183
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
265
305
HarmonyOS-ExamplesHarmonyOS-Examples
本仓将收集和展示仓颉鸿蒙应用示例代码,欢迎大家投稿,在仓颉鸿蒙社区展现你的妙趣设计!
Cangjie
398
371
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
1.07 K
0
ShopXO开源商城ShopXO开源商城
🔥🔥🔥ShopXO企业级免费开源商城系统,可视化DIY拖拽装修、包含PC、H5、多端小程序(微信+支付宝+百度+头条&抖音+QQ+快手)、APP、多仓库、多商户、多门店、IM客服、进销存,遵循MIT开源协议发布、基于ThinkPHP8框架研发
JavaScript
93
15
note-gennote-gen
一款跨平台的 Markdown AI 笔记软件,致力于使用 AI 建立记录和写作的桥梁。
TSX
83
4
cherry-studiocherry-studio
🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端
TypeScript
598
57
GitNextGitNext
基于可以运行在OpenHarmony的git,提供git客户端操作能力
ArkTS
10
3