You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ReadOnlyMemory反序列化protobuf-net失败,报错「Invalid wire type (VarInt)」原因?

问题

使用流进行protobuf反序列化时可以成功,但改用ReadOnlySpan<byte>实例替代流时,会抛出ProtoException异常,提示「Invalid wire type (VarInt)」。使用的protobuf-net版本为3.1.26。

复现代码:

using (var stream = new MemoryStream())
{
    var test = 1;
    Serializer.Serialize(stream, test);

    // 保存字节用于后续对比
    var bytes = stream.ToArray();

    // 反序列化成功
    stream.Seek(0, SeekOrigin.Begin);
    var item = Serializer.Deserialize<int>(stream);

    // 反序列化成功
    stream.Seek(0, SeekOrigin.Begin);
    var item2 = Serializer.Deserialize(typeof(int), stream);


    stream.Seek(0, SeekOrigin.Begin);
    var rom = new ReadOnlySpan<byte>(stream.ToArray());
    // 完整性校验:newBytes与bytes一致,实际确实一致
    var newBytes = rom.ToArray();

    // 此处抛出ProtoException异常:"Invalid wire-type (Varint)..."
    var item3 = Serializer.Deserialize(rom, typeof(int));
}
原因与解决方法

这个问题的核心是protobuf-net中针对流和针对ReadOnlySpan<byte>的序列化/反序列化逻辑存在格式差异:

  • 用Serializer.Serialize(stream, test)序列化单个int时,protobuf-net默认会写入带字段标识的完整protobuf结构(包含字段标签和wire type信息)。
  • 但调用Serializer.Deserialize(rom, typeof(int))时,该重载默认期望的是无字段标识的原始值格式(直接存储的varint数据,不带字段标签)。

两种格式不匹配,导致解析时识别到错误的wire type,抛出异常。

解决方法有两种:

  • 序列化时统一使用无字段标识格式:
    如果后续要通过ReadOnlySpan<byte>反序列化,序列化时调用针对Span<byte>的重载,确保格式一致:
    var buffer = new byte[Serializer.GetProtoMaxLength(test)];
    var length = Serializer.Serialize(buffer, test);
    var rom = new ReadOnlySpan<byte>(buffer, 0, length);
    var item3 = Serializer.Deserialize(rom, typeof(int));
    
  • 反序列化时明确解析带字段标识的结构:
    使用ProtoReader手动处理,先读取字段头信息再解析值:
    using var reader = new ProtoReader(rom, null, new ProtoReader.State());
    reader.ReadFieldHeader(); // 读取字段标签和wire type
    var item3 = reader.ReadInt32();
    

内容的提问来源于stack exchange,提问作者Elroy Flynn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 09:23:42