【问题标题】:Why won't enums deserialize with protobufs?为什么枚举不能用 protobufs 反序列化?
【发布时间】:2012-07-17 23:55:12
【问题描述】:

我有一个我序列化的类,然后使用 Protobuf-net 版本 r431(可能一岁左右)反序列化。该类包含一个枚举_type 和一个名为_band 的字符串。在构造函数中,_type 设置为 StationType.Other,_band 设置为空字符串。

如您所见,我用数据创建了一个对象,序列化,然后反序列化。枚举_type (StationType.Streaming) 的值丢失,而_band (FM) 被保留。

我觉得这是一个错误,因为行为不一致。但是,如果我从值 1 而不是 0 开始枚举,则一切都按预期工作(例如,所有值都被保留)。

我在这里遗漏了什么吗?请参阅下面的代码和输出:

using System;
using System.IO;
using ProtoBuf;

namespace ProtoBufsWithEnums
{
    class Program
    {
        static void Main(string[] args)
        {
            stn1 = new Station{Type = StationType.Streaming, Band = "FM"};

            var ms1 = new MemoryStream();
            Serializer.Serialize(ms1, stn1); // serialize
            byte[] bytes = ms1.ToArray();

            var ms2 = new MemoryStream(bytes);
            Station stn2 = Serializer.Deserialize<Station>(ms2); // deserialize

            Console.WriteLine("Type - Original {0}, New {1}", stn1.Type, stn2.Type);
            Console.WriteLine("Band - Original {0}, New {1}", stn1.Band, stn2.Band);
        }
    }

    [ProtoContract]
    public enum StationType
    {
        [ProtoEnum(Name = "Streaming", Value = 0)]
        Streaming = 0,
        [ProtoEnum(Name = "Terrestrial", Value = 1)]
        Terrestrial = 1,
        [ProtoEnum(Name = "Other", Value = 2)]
        Other = 2,
        [ProtoEnum(Name = "Group", Value = 3)]
        Group = 3
    }

    [ProtoContract]
    public class Station 
    {
        [ProtoMember(9)]
        private StationType _type;
        [ProtoMember(10)]
        private string _band;

        public Station()
        {
            _type = StationType.Other;
            _band = "";
        }

        public StationType Type
        {
            get { return _type; }
            set { _type = value; }
        }

        public string Band
        {
            get { return _band; }
            set { _band = value; }
        }
    }
}

输出:

Type - Original Streaming, New Terrestrial
Type - Original FM, New FM

编辑:在 protobuf-net 网站上找到 issue 251,不确定我是否正在查看相同的问题。不太确定它是否已修复。

【问题讨论】:

    标签: c# serialization protocol-buffers protobuf-net


    【解决方案1】:

    这是错误:

    public Station()
    {
        _type = StationType.Other;
        _band = "";
    }
    

    protobuf-net 对零默认值做了一些隐含的假设。这在很多情况下都很好,但不是全部。在这里帮助它的最简单方法是告诉它您使用的是非零默认值:

    [ProtoMember(9), DefaultValue(StationType.Other)]
    private StationType _type;
    

    另一种选择是告诉它总是序列化它:

    [ProtoMember(9, IsRequired = true)]
    private StationType _type;
    

    如果您有 很多 个这样的,另一个选项是禁用“零默认”行为,这可以在自定义模型上完成:

    var model = TypeModel.Create();
    model.UseImplicitZeroDefaults = false;
    

    然后使用model.Serialize(...) 等 - 但请注意,您应该存储和重复使用这样的模型(不要在每次需要序列化某些内容时重新创建它),因为它包含所有缓存的反射/元编程输出。

    【讨论】:

      【解决方案2】:

      请用[EnumMember]标记枚举

      例如:

       [DataContract]
       [ProtoContract]
          public enum StationType
          {
              [EnumMember]
              [ProtoEnum(Name = "Streaming", Value = 0)]
              Streaming = 0,
      
              [EnumMember]
              [ProtoEnum(Name = "Terrestrial", Value = 1)]
              Terrestrial = 1,
      
              [EnumMember]
              [ProtoEnum(Name = "Other", Value = 2)]
              Other = 2,
      
              [EnumMember]
              [ProtoEnum(Name = "Group", Value = 3)]
              Group = 3
          }
      

      【讨论】:

      • 没有效果。问题依然存在。
      • @Angryum Hacker 我忘了用 [DataContract] 标记枚举,请立即尝试
      • 其实,对于 protobuf-net,你不需要用任何东西来标记枚举
      猜你喜欢
      • 1970-01-01
      • 2019-05-31
      • 2015-07-26
      • 1970-01-01
      • 1970-01-01
      • 2015-10-19
      • 1970-01-01
      • 2021-11-30
      • 1970-01-01
      相关资源
      最近更新 更多