使用protobuf-net序列化[Flags]枚举时,InvalidOperationException [英] InvalidOperationException when serializing [Flags] enum with protobuf-net

查看:76
本文介绍了使用protobuf-net序列化[Flags]枚举时,InvalidOperationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试序列化用 [Flags] 属性修饰的 enum 类型. enum 声明如下:

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:由于对象的当前状态,操作无效.

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

在SO上的其他类似帖子之后,我尝试了以下操作:

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

    在我的枚举的ProtoContract属性中
  1. 添加 EnumPassthru = true 参数
  2. 在应用启动阶段使用 RuntimeTypeModel.Default [typeof(Categories)].EnumPassthru = true;
  3. 使用IsRequired参数 [ProtoMember(6,IsRequired = true)]
  4. 为容器对象的枚举值字段提供了内容
  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:由于对象的当前状态,操作无效.\ r \ n位于c:\ Users \ onur.gumus \ Desktop \ protobuf-net-中的ProtoBuf.Serializers.EnumSerializer.EnumToWire(Object value)master \ protobuf-net \ Serializers \ EnumSerializer.cs:行83 \ r \ n位于c:\ Users \ onur.gumus \ Desktop \ protobuf-net-master中的ProtoBuf.Serializers.EnumSerializer.Write(对象值,ProtoWriter dest)\ protobuf-net \ Serializers \ EnumSerializer.cs:行125 \ r \ n位于c:\ Users \ onur.gumus \ Desktop \ protobuf-net-master \中的ProtoBuf.Serializers.FieldDecorator.Write(对象值,ProtoWriter dest)protobuf-net \ Serializers \ FieldDecorator.cs:行38 \ r \ n位于c:\ Users \ onur.gumus \ Desktop \ protobuf-net-master \ protobuf中的ProtoBuf.Serializers.TypeSerializer.Write(对象值,ProtoWriter dest)-net \ Serializers \ TypeSerializer.cs:行173 \ r \ n位于c:\ Users \ onur中的ProtoBuf.Meta.TypeModel.TrySerializeAuxiliaryType(ProtoWriter writer,Type type,DataFormat format,Int32 tag,Object value,Boolean isInsideList).牙龈\Desktop \ protobuf-net-master \ protobuf-net \ Meta \ TypeModel.cs:第125行...

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 ...

推荐答案

在protobuf-net的所有容易获得的版本(即非古代)中, [Flags] 将激活直通行为,从而这项工作很好. [ProtoContract(EnumPassThru = true)] 也会 激活直通行为,但是如果指定了 [Flags] ,则是多余的.

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.

在2.3.0及更高版本中,只要您不具有实际更改序列化的值(但不要更改)-这与"proto3"更加一致,并且在大多数情况下可以更轻松地使用枚举.

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:

  • 具有2.3.0和2.0.0.668
  • 带有问题中的属性,并删除了除 [Flags] 以外的所有内容
  • 在2.3.0上,甚至删除了 [Flags] 属性(尽管我同意应保留在您的情况下-绝对是 [Flags] 枚举)
  • 以枚举为根值,并以枚举作为成员,在传入的对象上标记为 [ProtoMember]
  • 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);
    }
}

这篇关于使用protobuf-net序列化[Flags]枚举时,InvalidOperationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆