首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用protobuf-net进行枚举序列化

用protobuf-net进行枚举序列化
EN

Stack Overflow用户
提问于 2013-05-28 23:36:39
回答 1查看 2.7K关注 0票数 1

我在一个大型项目中更新了一个旧版本的protobuf到当前的版本(使用的版本大约是1-2年前)。我不认识牧师)。可悲的是,较新的版本会引发异常。

CreateWireTypeException在ProtoReader.cs第292行

在以下测试用例中:

代码语言:javascript
运行
复制
    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的r262 )中运行良好。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-05-29 07:28:56

简单地说,是一个bug;这是在r640中修复的(现在已经部署到NuGet和google中了),以及基于上面代码的附加测试,这样它就不会重新出现。

关于性能(注释);我要看的第一个提示是:“偏好组”。基本上,protobuf规范包含了包含子对象的两种不同方式--“组”和“长度-前缀”。组是最初的实现,但谷歌现在已经转向“长度前缀”,并试图建议人们不要使用“组”。不过!由于protobuf的工作原理,“组”的编写成本实际上要低得多;这是因为与google的实现不同,不是事先就知道事情的长度。这意味着要写入长度前缀,它需要执行以下操作之一:

  • 根据需要计算长度(几乎与实际序列化数据的工作量一样多,bud添加了整个代码副本);编写长度,然后实际序列化数据。
  • 序列化到缓冲区,写入长度,写入缓冲区
  • 保留一个位置保持器,序列化,然后循环回并将实际长度写入位置保持架,必要时调整垫子。

我已经在不同的时间实现了所有三种方法,但是v2使用了第三种方法。我一直在玩添加第四个实现:

  • 留下一个位置保持器,序列化,然后循环回写实际长度使用超长的形式(因此,从来不需要填充调整)

但是..。大家的共识似乎是,“超长形式”有一点风险;不过,对于protobuf来说,它会很好地工作。

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

  • 写入开始标记;序列化;写入结束标记

就是这样;不需要长度;写起来真的,真的,非常便宜。在导线上,它们之间的主要区别是:

  • 组:编写起来很便宜,但是如果遇到意外的数据,就不能跳过它们;您必须解析有效负载的头
  • 长度前缀:写起来更昂贵,但是如果遇到意外的数据,跳过它们就很便宜了--你只需读取长度并复制/移动那么多字节。

但!太多细节了!

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

代码语言:javascript
运行
复制
[ProtoContract]
public class SomeWrapper
{
    [ProtoMember(1)]
    public List<Person> People { get { return people; } }

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

您可以进行非常复杂的更改:

代码语言:javascript
运行
复制
[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,所有现有的数据都会很好。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16803233

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档