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

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

2025-06-04 12:10:54作者:苗圣禹Peter

问题背景

在使用MessagePack-CSharp进行Unity项目开发时,当切换到IL2CPP编译模式后,开发者可能会遇到一个常见的序列化问题:尝试序列化包含自定义类型数组的对象时,会抛出"Not supported primitive object resolver"异常。这个问题在Mono模式下通常不会出现,但在IL2CPP模式下却会引发错误。

问题分析

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

解决方案

要解决这个问题,我们需要创建一个自定义的解析器(Resolver)和格式化器(Formatter),专门用于处理包含自定义类型的对象数组。以下是实现步骤:

1. 创建自定义格式化器

首先,我们需要实现一个IMessagePackFormatter<object[]>接口的自定义格式化器,明确指定如何处理各种类型的数据:

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;
                case AirSimVector vector:
                    options.Resolver.GetFormatterWithVerify<AirSimVector>().Serialize(ref writer, vector, options);
                    break;
                case AirSimQuaternion quaternion:
                    options.Resolver.GetFormatterWithVerify<AirSimQuaternion>().Serialize(ref writer, quaternion, options);
                    break;
                case AirSimPose pose:
                    options.Resolver.GetFormatterWithVerify<AirSimPose>().Serialize(ref writer, pose, 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;
    }
}

2. 注册自定义解析器

接下来,我们需要在应用程序启动时注册这个自定义解析器:

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

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

技术要点

  1. 类型安全处理:自定义格式化器中通过switch-case语句明确处理每种支持的类型,确保类型安全。

  2. 性能考虑:直接调用writer.Write方法处理基本类型,避免不必要的反射开销。

  3. 扩展性:当需要支持新的自定义类型时,只需在格式化器中添加相应的case分支即可。

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

实际应用

在实际项目中,这种解决方案特别适用于RPC框架或网络通信场景,其中请求/响应对象可能包含各种不同类型的参数。例如:

[MessagePackObject]
public class RpcRequest
{
   [Key(0)] public int type { get; set; }
   [Key(1)] public int id { get; set; }
   [Key(2)] public string method { get; set; }
   [Key(3)] public object[] _Param { get; set; }
}

现在,_Param数组可以包含基本类型和自定义类型的混合数据,都能被正确序列化和反序列化。

注意事项

  1. 确保所有自定义类型都正确标记了[MessagePackObject]和[Key]属性。

  2. 对于反序列化部分,需要根据实际需求补充对自定义类型的处理逻辑。

  3. 在性能敏感的场景中,可以考虑进一步优化格式化器的实现,例如使用字典查找替代switch-case。

通过这种解决方案,开发者可以在IL2CPP模式下顺利使用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