はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】protobuf-netという非公式ライブラリを利用してProtocolBuffersを扱う方法

はじめに

今回はprotobuf-netというライブラリを利用して.NET上でprotocol buffersを扱う方法を紹介したいと思います。

www.nuget.org
github.com

概要

protobuf-netprotocol buffersのシリアライザーライブラリです。Google製ライブラリとしてGoogle.Protobufが挙げられますが、Unityで扱いづらいとの噂を聞いたことがあります(実際に試したわけではありません)。また後でここらへんを別記事にまとめようかなと思います。

www.nuget.org

protobuf-net is a contract based serializer for .NET code, that happens to write data in the "protocol buffers" serialization format engineered by Google. The API, however, is very different to Google's, and follows typical .NET patterns (it is broadly comparable, in usage, to XmlSerializer, DataContractSerializer, etc). It should work for most .NET languages that write standard types and can use attributes.

// DeepL翻訳
protobuf-netは、.NETコード用のコントラクトベースのシリアライザーで、Googleによって設計された「プロトコル・バッファ」シリアライゼーション・フォーマットでデータを書き込む。しかし、APIはGoogleのものとは大きく異なっており、典型的な.NETのパターンに従っている(XmlSerializerやDataContractSerializerなどと大まかな使い方は同じである)。標準的な型を記述し、属性を使用できるほとんどの.NET言語で動作するはずです。

GitHub - protobuf-net/protobuf-net: Protocol Buffers library for idiomatic .NET

またProtocol Buffersの原理が知りたい方は以下を参照してみてください。
developers.google.com

サポートされているバージョン

  • .NET 6.0+ (.NET 5 etc will use .NET Standard 2.1)
  • .NET Standard 2.0, 2.1
  • .NET Framework 4.6.2+

GitHub - protobuf-net/protobuf-net: Protocol Buffers library for idiomatic .NET

環境

  • Rider 2023.1.3
  • Console Application
  • .net7.0
  • C#11

インストール方法

Rider上のエクスプローラーから.csprojを右クリックし、NuGetパッケージの管理を選択します。

NuGetパッケージの管理

あとはprotobuf-netと検索して右上の+ボタンを押せばインストール完了です。

protobuf-netをインストール

Riderプラグインの導入

JetBrains製のProtocol Buffersプラグインがあるので、これを導入すると便利です。proto2proto3に対応しています。

Provides editor support for Protocol Buffers files.

plugins.jetbrains.com

導入方法は設定画面を開き、プラグイン > Protocol Buffers > インストールからインストールを行なってください。

Protocol Buffersプラグインをインストール

使い方

まずは.protoを利用せずに、素朴な実装から使い方を見ていきます。具体的に以下の操作を行いました。

  1. シリアライズ・デシリアライズ対象のclassに対して[ProtoContract]をつけ、メンバーに対して[ProtoMemberを付与
  2. ProtoBuf.Serializer.Serializeを利用してシリアライズ
  3. ProtoBuf.Serializer.Deserializeを利用してデシリアライズ
using ProtoBuf;

// ------------------------------
// Decorate your classes
// ------------------------------

// シリアライズ・デシリアライズ対象に[ProtoContract]をつける
[ProtoContract]
public class Person
{
    // [ProtoMember]で一意のtagをつけていく
    [ProtoMember(1)]
    public int Id { get; set; }
    
    [ProtoMember(2)]
    public string Name { get; set; }
    
    [ProtoMember(3)]
    public Address Address { get; set; }
}

[ProtoContract]
public class Address
{
    [ProtoMember(1)]
    public string Line1 { get; set; }
    
    [ProtoMember(2)]
    public string Line2 { get; set; }
}

// ------------------------------
// Serialize・Deserialize your data
// ------------------------------
internal class Program
{
    public static void Main()
    {
        var person = new Person
        {
            Id = 12345,
            Name = "Hanachiru",
            Address = new Address
            {
                Line1 = "Line 1",
                Line2 = "Line 2"
            }
        };
        
        // Serialize
        using (var file = File.Create("person.bin"))
        {
            // 実際に書き込まれるデータ(バイナリ) : 08 B9 60 12 09 48 61 6E 61 63 68 69 72 75 1A 10 0A 06 4C 69 6E 65 20 31 12 06 4C 69 6E 65 20 32
            Serializer.Serialize(file, person);
        }
        
        // Deserialize
        Person newPerson;
        using (var file = File.OpenRead("person.bin"))
        {
            newPerson = Serializer.Deserialize<Person>(file);
            
            // 12345
            Console.WriteLine(newPerson.Id);
            
            // Hanachiru
            Console.WriteLine(newPerson.Name);
            
            // Line 1
            Console.WriteLine(newPerson.Address.Line1);

            // Line 2
            Console.WriteLine(newPerson.Address.Line2);
        }
    }
}

実際に触ってみれば結構シンプルですね。覚えることは[ProtoContract][ProtoMember(1)]で一意のtagをつけるだけです。

.protoを利用する

.protoファイルを利用することで、上記の[ProtoContract]が付与されているクラスを自動生成できます。記法はProtobugの公式ドキュメント or MSの公式ドキュメント あたりを参照すると良いでしょう。(特にMSの公式Docがオススメ)
protobuf.dev
learn.microsoft.com

せっかくRiderにプラグインを入れたので、Rider上で以下のファイルを作成しました。

// sample.proto
syntax = "proto3";

option csharp_namespace = "Sample.Messages";

message Person
{
  // Protobugスタイルガイドではフィールド名にunderscore_separated_namesを利用することが推奨
  // .NET ツールでは自動で UnderScoreSeparatedNames のように変換してくれます
  int32 id = 1;
  string name = 2;
  Address address = 3;
}

message Address
{
  string line1 = 1;
  string line2 = 2;
}

.protoからコード生成する方法は複数ありますが、一番楽なのは以下のサイトを利用することでしょう。(GitHubのReadmeにこのやり方が記載されていた)
protogen.marcgravell.com

protogen.marcgravell.comを利用した例