Reputation: 125
I want to read fields of type "EnumValueOptions". All examples I have found are related to languages other than "C#".
There is a protocol:
syntax = "proto3";
import "google/protobuf/descriptor.proto";
extend google.protobuf.EnumValueOptions {
string enum_name = 51234;
};;
message Options {
enum Profiles{
A = 0 [(enum_name) = "AAA"];
B = 1 [(enum_name) = "BBB"];
C = 2 [(enum_name) = "CCC"];
};
Profiles profile = 1;
}
How to read "enum_name" in code C#?
expecting:
foreach(Profiles profile in Enum.GetValues(typeof(Profiles)))
{
string name = ????; //name in ("AAA","BBB","CCC")
}
Upvotes: 1
Views: 2654
Reputation: 169
I'm programming in C# - still pretty new to this protobuf stuff
If you have the following proto file extending the EnumValueOptions:
extend google.protobuf.EnumValueOptions {
string Value = 101;
bool AutoEnrol = 102;
}
Protobuf will produce a EnumValueOptionsExtensions class through auto-generation. To access it use EnumValueOptionsExtensions.Value or EnumValueOptionsExtensions.AutoEnrol, per the C# code sample a little later/below.
Then in the same or another proto file, create an enum with the following:
enum SystemRoleType {
ReservedRole = 0 [(Value) = "SystemRoleType.ReservedRole", (AutoEnrol) = false];
Administrator = 1001 [(Value) = "SystemRoleType.Administrator", (AutoEnrol) = false];
Editor = 1002 [(Value) = "SystemRoleType.Editor", (AutoEnrol) = false];
ContentCreator = 1003 [(Value) = "SystemRoleType.ContentCreator", (AutoEnrol) = false];
User = 1004 [(Value) = "SystemRoleType.ContentCreator", (AutoEnrol) = true];
}
Again, this will produce a SystemRoleTypeReflection class through protobuf auto-generation.
Then in C#, include your namespaces accordingly (that also includes: Google.Protobuf.Reflection) and then you could do something like the following in C#
EnumDescriptor SystemRoleTypeTypeEnumDescriptor = SystemRoleTypeReflection.Descriptor.FindTypeByName<EnumDescriptor>(typeof(SystemRoleType).Name);
foreach (SystemRoleType system_role_type in Enum.GetValues(typeof(SystemRoleType)))
{
EnumValueDescriptor enum_value_descriptor = SystemRoleTypeTypeEnumDescriptor.FindValueByNumber((int)system_role_type);
var selector_value = enum_value_descriptor.GetOptions().GetExtension<string>(EnumValueOptionsExtensions.Value);
var auto_enrolment = enum_value_descriptor.GetOptions().GetExtension<bool>(EnumValueOptionsExtensions.AutoEnrol);
}
Updated (2021-12-01): I put a tiny VS solution together today, that you can open in Visual Studio Community 2022 (.Net 6 / C# 10) and run the example in a console app: github.com/kibblewhite/EnumValueOptions-gRPC-Example
Upvotes: 2
Reputation: 21
Proto:
syntax = "proto2";
package my.protos;
option csharp_namespace = "My.Protos";
import "google/protobuf/descriptor.proto"; // For enum extension.
extend google.protobuf.EnumValueOptions {
optional string NameDisplay = 50001;
optional string NameAbbrev = 50002;
}
enum MyOperation {
MY_CREATE = 0 [(NameDisplay) = "create"];
MY_DELETE = 1 [(NameDisplay) = "delete"];
MY_READ = 2 [(NameDisplay) = "read"];
}
Usage in C#:
Google.Protobuf.Reflection.EnumDescriptor descriptor =
MyProtosReflection.Descriptor.FindTypeByName<Google.Protobuf.Reflection.EnumDescriptor>(
typeof(MyOperation).Name
);
Google.Protobuf.Reflection.EnumValueDescriptor valueDescriptor =
descriptor.FindValueByNumber((int)MyOperation.Create);
string nameDisplay = valueDescriptor.GetOption(MyProtosExtensions.NameDisplay);
Upvotes: 1
Reputation: 27404
Protobuf doesn't generate c# codes for enum value options, so if you want to retrieve these values, you need edit the source at src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
.
Here is an example
void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value)
{
WriteDocCommentBody(printer, value);
// Example code to prepend c# attribute like '[Custom(name: value)]' before a enum field
const Message& options = value->options();
const Reflection* reflection = options.GetReflection();
std::vector<const FieldDescriptor*> fields;
reflection->ListFields(options, &fields);
for (int i = 0; i < fields.size(); i++)
{
std::string name = fields[i]->full_name();
std::string fieldval;
TextFormat::PrintFieldValueToString(options, fields[i], -1, &fieldval);
printer->Print("[Custom($name$: $value$)]", "name", name, "value", fieldval);
}
}
Regenerate cs file then you can use GetCustomAttribute method to retrieve these information.
Upvotes: 1