1

我在一个大型项目中将旧版本的 protobuf 更新为当前版本(使用的版本大约有 1-2 年的历史。我不知道版本)。可悲的是,较新的版本引发了异常

ProtoReader.cs 第 292 行中的 CreateWireTypeException

在以下测试用例中:

    enum Test
    {
        test1 = 0,
        test2
    };
    static public void Test1()
    {
        Test original = Test.test2;
        using (MemoryStream ms = new MemoryStream())
        {
            Serializer.SerializeWithLengthPrefix<Test>(ms, original, PrefixStyle.Fixed32, 1);
            ms.Position = 0;
            Test obj;
            obj = Serializer.DeserializeWithLengthPrefix<Test>(ms, PrefixStyle.Fixed32);
        }
    }

我发现枚举不应该直接在类之外序列化,但是我们的系统太大而无法简单地将所有枚举包装在类中。这个问题还有其他解决方案吗?它仅适用于序列化和反序列化DeserializeWithLengthPrefix抛出异常。

测试用例在旧版本中运行良好,例如 protobuf-net 的 r262。

4

1 回答 1

3

简单地说,一个错误;这在 r640(现在部署到 NuGet 和 google-code)中已修复,以及基于您上面的代码的附加测试,因此它不会重新进入。


重新表现(评论);我要看的第一个提示是:“更喜欢团体”。基本上,protobuf 规范包括 2 种不同的方式来包含子对象——“组”和“长度前缀”。组是最初的实现,但谷歌现在已经转向“长度前缀”,并试图建议人们不要使用“组”。然而!由于 protobuf-net 的工作方式,“组”实际上写起来要便宜得多。这是因为与 google 实现不同,protobuf-net事先并不知道事物的长度。这意味着要编写长度前缀,它需要执行以下操作之一:

  • 根据需要计算长度(几乎与实际序列化数据一样多的工作,bud 添加代码的完整副本);写入长度,然后实际序列化数据
  • 序列化到缓冲区,写入长度,写入缓冲区
  • 留下一个占位符,序列化,然后循环返回并将实际长度写入占位符,如果需要调整填充

我在不同时间实现了所有 3 种方法,但 v2 使用第 3 个选项。我一直在玩弄添加第四个实现:

  • 留下一个占位符,序列化,然后循环返回并使用超长形式写入实际长度(因此不需要填充调整)

但是……共识似乎是“超长形式”有点冒险;尽管如此,它仍然可以很好地用于 protobuf-net 到 protobuf-net。

但是正如你所看到的:长度前缀总是有一些开销。现在想象一下嵌套相当深的对象,你可以看到一些光点。小组的工作方式非常不同;组的编码格式为:

  • 写一个开始标记;连载; 写一个结束标记

而已; 不需要长度;真的,真的,真的很便宜写。在电线上,它们之间的主要区别是:

  • groups:写起来很便宜,但是如果遇到意外数据就不能跳过它们;您必须解析有效负载的标头
  • 长度前缀:写入成本更高,但如果您将它们作为意外数据遇到则跳过它们很便宜 - 您只需读取长度并复制/移动那么多字节

但!太详细了!

这对你意味着什么?好吧,想象一下你有:

[ProtoContract]
public class SomeWrapper
{
    [ProtoMember(1)]
    public List<Person> People { get { return people; } }

    private readonly List<Person> people = new List<Person>();
}

您可以进行超级复杂的更改:

[ProtoContract]
public class SomeWrapper
{
    [ProtoMember(1, DataFormat=DataFormat.Group)]
    public List<Person> People { get { return people; } }

    private readonly List<Person> people = new List<Person>();
}

它将使用更便宜的编码方案。只要您使用 protobuf-net,您现有的所有数据都可以。

于 2013-05-29T07:28:56.600 回答