messagepackserializer.serialize 输出乱码是因为它是二进制格式,须用file.writeallbytes或stream写入原始字节,不可用字符串方法处理;自定义类需加[messagepackobject]和[key(n)]标记才能序列化。

MessagePackSerializer.Serialize 为什么序列化出来全是乱码?
因为 MessagePack 是二进制格式,不是文本。直接用 File.WriteAllText 或写入字符串流会破坏字节,导致“乱码”或反序列化失败。
- 必须用
File.WriteAllBytes写入原始字节,或用Stream(如FileStream)配合MessagePackSerializer.Serialize - 别试图用
Encoding.UTF8.GetString(bytes)去“看内容”——这不是设计来给人读的 - 调试时想确认是否正常,可用
Convert.ToBase64String(bytes)短暂转成可读字符串,但仅限调试,不可用于存储或传输
如何让自定义类支持 MessagePack 序列化?
默认情况下,MessagePackSerializer.Serialize 无法处理未标记的普通 class,会抛出 NotSupportedException: Type xxx is not supported。
- 最简单方式:给类加
[MessagePackObject],每个要序列化的字段/属性加[Key(n)](n 为整数 ID,建议从 0 开始连续) - 不加
[Key]也能工作,但需启用契约生成器(见下一点),否则仍失败 - 注意字段访问修饰符:
private字段默认不被序列化,除非显式加[SerializationConstructor]或开启ContractlessStandardResolver.Options
[MessagePackObject]
public class User
{
[Key(0)] public string Name { get; set; }
[Key(1)] public int Age { get; set; }
}
使用 ContractlessStandardResolver 后性能反而变差?
是的,开合约无关模式(contractless)会让 MessagePack 放弃预生成序列化器,每次调用都反射推导结构,显著拖慢速度,尤其在高频小对象场景。
- 仅在原型开发或类型极动态(如
ExpandoObject)时临时启用:MessagePackSerializerOptions.Standard.WithResolver(ContractlessStandardResolver.Instance) - 生产环境务必用带
[MessagePackObject]的显式契约,并配合MessagePackSerializer.GetFormatter<t>()</t>预热 - 首次序列化某个类型时最慢,后续会缓存;但 contractless 模式下缓存粒度更粗、命中率更低
文件序列化后体积比 JSON 还大?
通常不会,MessagePack 二进制格式本应更紧凑。体积异常往往源于没关掉兼容性选项或用了低效配置。
- 检查是否误启用了
CompatibilityOptions(如UseSimpleAssemblyName = false),这会让类型名全路径写入,大幅膨胀 - 避免序列化含大量空值或默认值的字段——MessagePack 不自动跳过,需手动用
[IgnoreDataMember]或[SkipIfDefault] - 数组和字典默认不压缩重复键,如果键固定(如日志事件中的
"timestamp","level"),考虑用Dictionary<byte object></byte>或预定义 schema 替代 string key










