Kirill Muratov
Kirill Muratov

Reputation: 368

Protobuf-net serialize enum with value out of range

C# allows to assign any integer value to enum.

When I try to serialize (via protobuf-net) object with enum field which value is out of range, it throws exception: No wire-value is mapped to the enum PersonLevel.

My enum PersonLevel doesn't have Flags attribute.

[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public enum PersonLevel
{
  Unknown = 1
}

[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public class Person
{
  ...

  public PersonLevel PersonLevel { get; set; }

  ...
}
var ms = new MemoryStream();

var person = new Person
{
  ...
  PersonLevel = (PersonLevel) 500
  ...
};

Serializer.Serialize(ms, person); //No wire-value is mapped to the enum PersonLevel

Is there any facilities to do it without changing business objects (maybe any protobuf attrubutes)?

Upvotes: 3

Views: 4266

Answers (2)

Marc Gravell
Marc Gravell

Reputation: 1063664

There are a couple of ways of telling it to simplify the rules; as Ravadre notes, [Flags] automatically disables validation - it causes EnumPassthru to become toggled. You can also do this manually - as long as it is before you start serializing / deserializing:

RuntimeTypeModel.Default[typeof(PersonLevel)].EnumPassthru = true;

which has the description:

/// <summary>
/// Gets or sets a value indicating that an enum should be treated directly as an int/short/etc, rather
/// than enforcing .proto enum rules. This is useful *in particular* for [Flags] enums.
/// </summary>

Upvotes: 6

Marcin Deptuła
Marcin Deptuła

Reputation: 11977

What you can do is create an int field which you will pack into protobuf message and expose a Property, which will expose your int field as an enum of your type (being a wrapper).

This might be harder if you are using implicit fields, because probably protobuf will try to serialize both, your integer and your enum property. You can try to explicitly [ProtoIgnore] your enum property.

However, protobuf does this automatically for you if your enum is marked with [Flags] attribute, so changing your enum to:

[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
[Flags]
public enum PersonLevel
{
    Unknown = 1
}

should make it work. At least in version 2.

Upvotes: 2

Related Questions