InvalidOperationException when serializing [Flags] enum with protobuf-net

二次信任 提交于 2019-12-10 19:30:43

问题


I am trying to serialize an enum type that is decorated with [Flags] attribute. The enum declaration is as follows:

[Flags]
[ProtoContract(EnumPassthru = true)]
public enum Categories
{
    [ProtoEnum(Name = nameof(Invalid), Value = 0x0)]
    Invalid = 0x0,

    [ProtoEnum(Name = nameof(A), Value = 0x1)]
    A = 0x1,
    [ProtoEnum(Name = nameof(B), Value = 0x2)]
    B = 0x2,
    [ProtoEnum(Name = nameof(C), Value = 0x4)]
    C = 0x4,
    [ProtoEnum(Name = nameof(D), Value = 0x8)]
    D = 0x8,
    [ProtoEnum(Name = nameof(Global), Value = 0x1 | 0x2 | 0x4 | 0x8)]
    Global = A | B | C | D,
}

Now, when I try to serialize the container object, I get

InvalidOperationException:Operation is not valid due to the current state of the object.

Following other similar posts on SO, I have tried the following:

  1. Add EnumPassthru = true parameter in my enum's ProtoContract attribute
  2. Use RuntimeTypeModel.Default[typeof(Categories)].EnumPassthru = true; at the app startup phase,
  3. Provided the container object's enum-valued field with the IsRequired parameter [ProtoMember(6, IsRequired = true)]

Is there anything else that I miss with my enum declaration?

The beginning of the exception detail goes like:

InvalidOperationException:Operation is not valid due to the current state of the object.\r\n at ProtoBuf.Serializers.EnumSerializer.EnumToWire(Object value) in c:\Users\onur.gumus\Desktop\protobuf-net-master\protobuf-net\Serializers\EnumSerializer.cs:line 83\r\n at ProtoBuf.Serializers.EnumSerializer.Write(Object value, ProtoWriter dest) in c:\Users\onur.gumus\Desktop\protobuf-net-master\protobuf-net\Serializers\EnumSerializer.cs:line 125\r\n at ProtoBuf.Serializers.FieldDecorator.Write(Object value, ProtoWriter dest) in c:\Users\onur.gumus\Desktop\protobuf-net-master\protobuf-net\Serializers\FieldDecorator.cs:line 38\r\n at ProtoBuf.Serializers.TypeSerializer.Write(Object value, ProtoWriter dest) in c:\Users\onur.gumus\Desktop\protobuf-net-master\protobuf-net\Serializers\TypeSerializer.cs:line 173\r\n at ProtoBuf.Meta.TypeModel.TrySerializeAuxiliaryType(ProtoWriter writer, Type type, DataFormat format, Int32 tag, Object value, Boolean isInsideList) in c:\Users\onur.gumus\Desktop\protobuf-net-master\protobuf-net\Meta\TypeModel.cs:line 125 ...


回答1:


In all easily available (i.e. not ancient) versions of protobuf-net, [Flags] will activate pass-thru behaviour, making this work fine. [ProtoContract(EnumPassThru = true)] will also activate pass-thru behaviour, but is redundant if [Flags] is specified.

In 2.3.0 and above, pass-thru behaviour is also assumed by default as long as you don't have any [ProtoEnum] attributes that actually change the serialized value (which: yours do not) - this is to be more consistent with "proto3", and to make it easier to work with enums in the vast majority of cases.

So: it should not be necessary to do anything here - your code should already just work.

I've tried your code:

  • with 2.3.0 and 2.0.0.668
  • with the attributes in the question, and with everything except [Flags] removed
  • on 2.3.0 with even the [Flags] attribute removed (although I agree it should be retained in your case - that is definitely a [Flags] enum)
  • with the enum as the root value, and with the enum as a member marked [ProtoMember] on an object passed in

In all cases it worked fine. So: in the general case, all I can say is that what you have should already work.

If it is failing in a specific case, it would be great to include a full runnable sample in the question (ideally telling us exactly what framework you are running on), so we can see what you are seeing. This works fine, for example:

using ProtoBuf;
using System;

[Flags]
public enum Categories
{
    Invalid = 0x0,
    A = 0x1,
    B = 0x2,
    C = 0x4,
    D = 0x8,
    Global = A | B | C | D,
}
[ProtoContract]
public class X
{
    [ProtoMember(1)]
    public Categories Val { get; set; }
    public override string ToString() => Val.ToString();
}
static class P
{
    static void Main()
    {
        var orig = new X { Val = Categories.D | Categories.B };
        var cloneObj = Serializer.DeepClone(orig);
        Console.WriteLine(cloneObj);

        var cloneEnum = Serializer.DeepClone(orig.Val);
        Console.WriteLine(cloneEnum);
    }
}


来源:https://stackoverflow.com/questions/45220365/invalidoperationexception-when-serializing-flags-enum-with-protobuf-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!