5

For the following Protocol Buffer message (proto3) how to I determine which type is set? There does not seem to be a "has_reply" method as is the case for the generated C++ version.

message Event {
  oneof type {
    Connection connection = 1;
    StatusReply reply = 2;
    Error error = 3;
    End end = 4;
    Empty empty = 5;
  };
}
kyrre
  • 626
  • 2
  • 9
  • 24

1 Answers1

8

https://developers.google.com/protocol-buffers/docs/reference/csharp-generated#oneof suggests that TypeOneofCase will tell you which is set:

Oneof Fields

Each field within a oneof has a separate property, like a regular singular field. However, the compiler also generates an additional property to determine which field in the enum has been set, along with an enum and a method to clear the oneof. For example, for this oneof field definition

oneof avatar {
  string image_url = 1;
  bytes image_data = 2;
}

The compiler will generate these public members:

enum AvatarOneofCase
{
  None = 0,
  ImageUrl = 1,
  ImageData = 2
}

public AvatarOneofCase AvatarCase { get; }
public void ClearAvatar();
public string ImageUrl { get; set; }
public ByteString ImageData { get; set; }

If a property is the current oneof "case", fetching that property will return the value set for that property. Otherwise, fetching the property will return the default value for the property's type - only one member of a oneof can be set at a time.

Setting any constituent property of the oneof will change the reported "case" of the oneof. As with a regular singular field, you cannot set a oneof field with a string or bytes type to a null value. Setting a message-type field to null is equivalent to calling the oneof-specific Clear method.

mjwills
  • 23,389
  • 6
  • 40
  • 63
  • 1
    > Otherwise, fetching the property will return the default value for the property's type - only one member of a oneof can be set at a time. This is awful! Default value and not set are not the same! This essentially makes the C# implementation oneof useless. – Isen Ng Nov 22 '18 at 09:15
  • 1
    @IsenGrim What is the alternative though (i.e. how would you build it otherwise)? `ImageUrl` is a `string` - so it fundamentally needs to return something that is actually a `string` - it can't return something else. The key bit here is to read the `AvatarCase` property before deciding whether to read `ImageUrl` or `ImageData`. – mjwills Nov 22 '18 at 09:42