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

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

2025-06-04 17:18:02作者:苗圣禹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序列化包含自定义类型的复杂对象,同时保持代码的清晰和可维护性。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
22
6
docsdocs
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
168
2.05 K
openHiTLS-examplesopenHiTLS-examples
本仓将为广大高校开发者提供开源实践和创新开发平台,收集和展示openHiTLS示例代码及创新应用,欢迎大家投稿,让全世界看到您的精巧密码实现设计,也让更多人通过您的优秀成果,理解、喜爱上密码技术。
C
99
608
nop-entropynop-entropy
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
8
0
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
199
279
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
954
563
金融AI编程实战金融AI编程实战
为非计算机科班出身 (例如财经类高校金融学院) 同学量身定制,新手友好,让学生以亲身实践开源开发的方式,学会使用计算机自动化自己的科研/创新工作。案例以量化投资为主线,涉及 Bash、Python、SQL、BI、AI 等全技术栈,培养面向未来的数智化人才 (如数据工程师、数据分析师、数据科学家、数据决策者、量化投资人)。
Python
78
71
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Java
60
17
apintoapinto
基于golang开发的网关。具有各种插件,可以自行扩展,即插即用。此外,它可以快速帮助企业管理API服务,提高API服务的稳定性和安全性。
Go
22
0