はじめに
今回はprotobuf
のカスタムオプションをC#で取り出す方法を紹介したいと思います。
protobuf.dev
// カスタムオプションを定義 extend google.protobuf.MessageOptions { string my_option = 50000; } message MyMessage { // "Hello, world!"をC#上で取り出したい option (my_option) = "Hello world!"; string message = 1; }
カスタムオプションの定義
見落としてるものがあるかもしれませんが、以下のオプションに対してカスタムオプションという形で拡張することができます。
EnumOptions
EnumValueOptions
FieldOptions
FileOptions
MessageOptions
MethodOptions
OneofOptions
ServiceOptions
例えばMessageOptions
を拡張してみます。
// example.proto syntax = "proto3"; import "google/protobuf/descriptor.proto"; option csharp_namespace = "Protobuf.Sample"; // メッセージ定義にカスタムオプションを追加 extend google.protobuf.MessageOptions { string my_option = 50000; } // メッセージ定義 message MyMessage { // 上で定義したカスタムオプションを使用 option (my_option) = "Hello world!"; string message = 1; }
一応1000
以上は利用してOKですが、すでにグローバルで一意な番号を予約がちょこちょこされているようです。自身で定義する場合は50000-99999
を利用するのが良いらしいです。
github.com
github.com
// google/protobuf/descriptor.protoの一部抜粋 message MessageOptions { optional bool message_set_wire_format = 1 [default=false]; optional bool no_standard_descriptor_accessor = 2 [default=false]; optional bool deprecated = 3 [default=false]; optional bool map_entry = 7; reserved 8; // javalite_serializable reserved 9; // javanano_as_lite repeated UninterpretedOption uninterpreted_option = 999; // 1000 ~ 536870911をカスタムオプション用に用意 extensions 1000 to max; }
One last thing: Since custom options are extensions, they must be assigned field numbers like any other field or extension. In the examples earlier, we have used field numbers in the range 50000-99999. This range is reserved for internal use within individual organizations, so you can use numbers in this range freely for in-house applications.
// DeepL翻訳
最後にもうひとつ、カスタムオプションは拡張機能なので、他のフィールドや拡張機能と同じようにフィールド番号を割り当てる必要があります。先ほどの例では、50000-999999の範囲のフィールド番号を使いました。この範囲は、個々の組織内での内部使用のために予約されているので、社内のアプリケーションではこの範囲の番号を自由に使うことができます。
Language Guide (proto 2) | Protocol Buffers Documentation
コンパイル
protoc
でコード生成された.cs
を通してカスタムオプションを取得していくので、コード生成を行っておく必要があります。
$ protoc example.proto --csharp_out="."
カスタムオプションを取得する
Google.Protobuf.Reflection
のDescriptor
を通してカスタムオプションを取得します。
- EnumDescriptor
- EnumValueDescriptor
- FieldDescriptor
- FileDescriptor
- MessageDescriptor
- MethodDescriptor
- OneofDescriptor
- ServiceDescriptor
MessageDescriptor.GetOptions
を実行してオプションを取得した後、MessageOptions.GetExtension
で値を取り出します。
Class MessageOptions (3.27.1) | .NET client library | Google Cloud
using Google.Protobuf.Reflection; using Protobuf.Sample; // MessageDescriptorを取得 MessageDescriptor descriptor = MyMessage.Descriptor; // オプションを取得 MessageOptions options = descriptor.GetOptions(); // MyMessageからMyOptionを取り出す // example.proto => ExampleExtensions if (options.HasExtension(ExampleExtensions.MyOption)) { // Hello world! Console.WriteLine(options.GetExtension(ExampleExtensions.MyOption)); }