Grpc.Tools で生成される C# ソースコードの解説

## このドキュメントの内容 ##

`Grpc.Tools`は proto ファイル（`ProtocolBuffers`のIDL定義ファイル）から各プログラム言語のソースコードを生成するためのツールです。この`Grpc.Tools`で生成される C# のソースコードの内容を確認します。 proto ファイルを使わずに直接コーディングするときの参考にしてください。

## 使用バージョン ##

* Grpc.Tools 1.14.1

## proto ファイル ##

次の型を定義しました。

| 型 | 種類 | 説明 |
|---|---|---|
| Positions | enum | ポジションを表すビットフラグ |
| Player | message | 選手 |
| Team | message | チーム |
| PlayerSearchCondition | message | 選手の検索条件 |
| PlayerSearch | service | 選手検索サービス |

```proto:PlayerService.proto

syntax = "proto3";

// 名前空間
option csharp_namespace = "mxProject.Examples";

// ポジション
enum Positions
{
	Unknown = 0;
	GK = 1;
	DF = 2;
	MF = 4;
	FW = 8;
}

// 選手
message Player
{
	string Name = 1;
	int32 Age = 2;
	Positions Positions = 3;
	Team Team = 4; 
}

// チーム
message Team
{
	string Name = 1;
	string League = 2;
}

// 選手の検索条件
message PlayerSearchCondition
{
	string PlayerName = 1;
	string TeamName = 2;
	string League = 3;
	Positions Positions = 4;
}

// 選手検索サービス
service PlayerSearch
{
	rpc SearchPlayer (PlayerSearchCondition) returns (stream Player){}
}
```

## バッチファイル ##

protoc を実行するバッチファイルを作成しました。

```generate.bat

set PROTOC_DIR=..\..\Grpc.Tools\
set MODEL_DIR=..\Models\
set SERVICE_DIR=..\Services\

%PROTOC_DIR%protoc PlayerService.proto --csharp_out %MODEL_DIR% --grpc_out %SERVICE_DIR% --plugin=protoc-gen-grpc=%PROTOC_DIR%grpc_csharp_plugin.exe

```

ディレクトリ・ファイル構成は次の通りです。

* ConsoleApp1
    * Models
        * ここに PlayerService.cs が生成されます。
    * Proto
        * generate.bat
        * PlayerService.proto
    * Services
        * ここに PlayerServiceGrpc.cs が生成されます。
* Grpc.Tools
    * grpc_csharp_plugin.exe
    * protoc.exe


## C# ソースコード（エンティティ） ##

| 型 | 種類 | 説明 |
|---|---|---|
| Positions | enum | ポジションを表すビットフラグ |
| Player | class | 選手 |
| Team | class | チーム |
| PlayerSearchCondition | class | 選手の検索条件 |
| PlayerServiceReflection | class | ProtocolBuffers 関連のリフレクション処理で用いられる定義クラス<br>アプリケーションコードから直接使用することはあまりないと思います |

* message は public sealed partial クラスとして定義されます。enum は 列挙体として定義されます。

* クラスには `OnConstruction`という partial メソッドが定義されており、コンストラクタの中で呼び出されています。インスタンス生成時に行いたい追加の処理がある場合、partial ファイルでこのメソッドの本体を実装します。

* `WriteTo`と`MergeFrom`というシリアライズ用メソッドが定義されています。

* `Clone`メソッドが定義されています。「深いコピー」です。
  
* `Equals`メソッドがオーバーライドされています。同じ参照である場合は true を返します。異なる参照であっても、全てのプロパティの値が等しければ true を返します。これは.NET の標準的な参照型の挙動と異なります。== 演算子はオーバーロードされていませんので、参照が異なれば false を返します。RPCメソッド呼び出しに関わる狭いスコープ内での利用に留まらずアプリケーション内で広く利用するケースでは、誤用しないように注意する必要があると思います。

```C#

Player p1 = new Player() { Name = "a" };
Player p2 = new Player() { Name = "a" };

Console.WriteLine(p1.Equals(p2));
Console.WriteLine(p1 == p2);
True
False
```

* `GetHashCode`メソッドがオーバーライドされています。各プロパティの値のハッシュコードの XOR を返します。値型によく見られる実装です。これも .NET の標準的な参照型とは挙動が異なります。

```C#

Player p1 = new Player() { Name = "a" };
Player p2 = new Player() { Name = "a" };

// p2 は重複していると扱われて格納されません
HashSet<Player> hash = new HashSet<Player>();
hash.Add(p1);
hash.Add(p2);

// p2 は重複していると扱われて ArgumentException がスローされます
Dictionary<Player, bool> dic = new Dictionary<Player, bool>();
dic.Add(p1, true);
dic.Add(p2, true);
```

#### 生成されたソースコード ####

```c#:PlayerService.cs

// <auto-generated>
//     Generated by the protocol buffer compiler.  DO NOT EDIT!
//     source: PlayerService.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code

using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace mxProject.Examples {

  /// <summary>Holder for reflection information generated from PlayerService.proto</summary>
  public static partial class PlayerServiceReflection {

    #region Descriptor
    /// <summary>File descriptor for PlayerService.proto</summary>
    public static pbr::FileDescriptor Descriptor {
      get { return descriptor; }
    }
    private static pbr::FileDescriptor descriptor;

    static PlayerServiceReflection() {
      byte[] descriptorData = global::System.Convert.FromBase64String(
          string.Concat(
            "ChNQbGF5ZXJTZXJ2aWNlLnByb3RvIlcKBlBsYXllchIMCgROYW1lGAEgASgJ",
            "EgsKA0FnZRgCIAEoBRIdCglQb3NpdGlvbnMYAyABKA4yCi5Qb3NpdGlvbnMS",
            "EwoEVGVhbRgEIAEoCzIFLlRlYW0iIgoEVGVhbRIMCgRDb2RlGAEgASgJEgwK",
            "BE5hbWUYAiABKAkiXAoVUGxheWVyU2VhcmNoQ29uZGl0aW9uEhIKClBsYXll",
            "ck5hbWUYASABKAkSEAoIVGVhbU5hbWUYAiABKAkSHQoJUG9zaXRpb25zGAMg",
            "ASgOMgouUG9zaXRpb25zKjgKCVBvc2l0aW9ucxILCgdVbmtub3duEAASBgoC",
            "R0sQARIGCgJERhACEgYKAk1GEAQSBgoCRlcQCDJDCgxQbGF5ZXJTZWFyY2gS",
            "MwoMU2VhcmNoUGxheWVyEhYuUGxheWVyU2VhcmNoQ29uZGl0aW9uGgcuUGxh",
            "eWVyIgAwAUIVqgISbXhQcm9qZWN0LkV4YW1wbGVzYgZwcm90bzM="));
      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
          new pbr::FileDescriptor[] { },
          new pbr::GeneratedClrTypeInfo(new[] {typeof(global::mxProject.Examples.Positions), }, new pbr::GeneratedClrTypeInfo[] {
            new pbr::GeneratedClrTypeInfo(typeof(global::mxProject.Examples.Player), global::mxProject.Examples.Player.Parser, new[]{ "Name", "Age", "Positions", "Team" }, null, null, null),
            new pbr::GeneratedClrTypeInfo(typeof(global::mxProject.Examples.Team), global::mxProject.Examples.Team.Parser, new[]{ "Code", "Name" }, null, null, null),
            new pbr::GeneratedClrTypeInfo(typeof(global::mxProject.Examples.PlayerSearchCondition), global::mxProject.Examples.PlayerSearchCondition.Parser, new[]{ "PlayerName", "TeamName", "Positions" }, null, null, null)
          }));
    }
    #endregion

  }
  #region Enums
  public enum Positions {
    [pbr::OriginalName("Unknown")] Unknown = 0,
    [pbr::OriginalName("GK")] Gk = 1,
    [pbr::OriginalName("DF")] Df = 2,
    [pbr::OriginalName("MF")] Mf = 4,
    [pbr::OriginalName("FW")] Fw = 8,
  }

  #endregion

  #region Messages
  public sealed partial class Player : pb::IMessage<Player> {
    private static readonly pb::MessageParser<Player> _parser = new pb::MessageParser<Player>(() => new Player());
    private pb::UnknownFieldSet _unknownFields;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pb::MessageParser<Player> Parser { get { return _parser; } }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pbr::MessageDescriptor Descriptor {
      get { return global::mxProject.Examples.PlayerServiceReflection.Descriptor.MessageTypes[0]; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    pbr::MessageDescriptor pb::IMessage.Descriptor {
      get { return Descriptor; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public Player() {
      OnConstruction();
    }

    partial void OnConstruction();

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public Player(Player other) : this() {
      name_ = other.name_;
      age_ = other.age_;
      positions_ = other.positions_;
      Team = other.team_ != null ? other.Team.Clone() : null;
      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public Player Clone() {
      return new Player(this);
    }

    /// <summary>Field number for the "Name" field.</summary>
    public const int NameFieldNumber = 1;
    private string name_ = "";
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string Name {
      get { return name_; }
      set {
        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
      }
    }

    /// <summary>Field number for the "Age" field.</summary>
    public const int AgeFieldNumber = 2;
    private int age_;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public int Age {
      get { return age_; }
      set {
        age_ = value;
      }
    }

    /// <summary>Field number for the "Positions" field.</summary>
    public const int PositionsFieldNumber = 3;
    private global::mxProject.Examples.Positions positions_ = 0;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public global::mxProject.Examples.Positions Positions {
      get { return positions_; }
      set {
        positions_ = value;
      }
    }

    /// <summary>Field number for the "Team" field.</summary>
    public const int TeamFieldNumber = 4;
    private global::mxProject.Examples.Team team_;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public global::mxProject.Examples.Team Team {
      get { return team_; }
      set {
        team_ = value;
      }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override bool Equals(object other) {
      return Equals(other as Player);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public bool Equals(Player other) {
      if (ReferenceEquals(other, null)) {
        return false;
      }
      if (ReferenceEquals(other, this)) {
        return true;
      }
      if (Name != other.Name) return false;
      if (Age != other.Age) return false;
      if (Positions != other.Positions) return false;
      if (!object.Equals(Team, other.Team)) return false;
      return Equals(_unknownFields, other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override int GetHashCode() {
      int hash = 1;
      if (Name.Length != 0) hash ^= Name.GetHashCode();
      if (Age != 0) hash ^= Age.GetHashCode();
      if (Positions != 0) hash ^= Positions.GetHashCode();
      if (team_ != null) hash ^= Team.GetHashCode();
      if (_unknownFields != null) {
        hash ^= _unknownFields.GetHashCode();
      }
      return hash;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override string ToString() {
      return pb::JsonFormatter.ToDiagnosticString(this);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void WriteTo(pb::CodedOutputStream output) {
      if (Name.Length != 0) {
        output.WriteRawTag(10);
        output.WriteString(Name);
      }
      if (Age != 0) {
        output.WriteRawTag(16);
        output.WriteInt32(Age);
      }
      if (Positions != 0) {
        output.WriteRawTag(24);
        output.WriteEnum((int) Positions);
      }
      if (team_ != null) {
        output.WriteRawTag(34);
        output.WriteMessage(Team);
      }
      if (_unknownFields != null) {
        _unknownFields.WriteTo(output);
      }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public int CalculateSize() {
      int size = 0;
      if (Name.Length != 0) {
        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
      }
      if (Age != 0) {
        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Age);
      }
      if (Positions != 0) {
        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Positions);
      }
      if (team_ != null) {
        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Team);
      }
      if (_unknownFields != null) {
        size += _unknownFields.CalculateSize();
      }
      return size;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(Player other) {
      if (other == null) {
        return;
      }
      if (other.Name.Length != 0) {
        Name = other.Name;
      }
      if (other.Age != 0) {
        Age = other.Age;
      }
      if (other.Positions != 0) {
        Positions = other.Positions;
      }
      if (other.team_ != null) {
        if (team_ == null) {
          team_ = new global::mxProject.Examples.Team();
        }
        Team.MergeFrom(other.Team);
      }
      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(pb::CodedInputStream input) {
      uint tag;
      while ((tag = input.ReadTag()) != 0) {
        switch(tag) {
          default:
            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
            break;
          case 10: {
            Name = input.ReadString();
            break;
          }
          case 16: {
            Age = input.ReadInt32();
            break;
          }
          case 24: {
            positions_ = (global::mxProject.Examples.Positions) input.ReadEnum();
            break;
          }
          case 34: {
            if (team_ == null) {
              team_ = new global::mxProject.Examples.Team();
            }
            input.ReadMessage(team_);
            break;
          }
        }
      }
    }

  }

  public sealed partial class Team : pb::IMessage<Team> {
    private static readonly pb::MessageParser<Team> _parser = new pb::MessageParser<Team>(() => new Team());
    private pb::UnknownFieldSet _unknownFields;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pb::MessageParser<Team> Parser { get { return _parser; } }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pbr::MessageDescriptor Descriptor {
      get { return global::mxProject.Examples.PlayerServiceReflection.Descriptor.MessageTypes[1]; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    pbr::MessageDescriptor pb::IMessage.Descriptor {
      get { return Descriptor; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public Team() {
      OnConstruction();
    }

    partial void OnConstruction();

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public Team(Team other) : this() {
      code_ = other.code_;
      name_ = other.name_;
      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public Team Clone() {
      return new Team(this);
    }

    /// <summary>Field number for the "Code" field.</summary>
    public const int CodeFieldNumber = 1;
    private string code_ = "";
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string Code {
      get { return code_; }
      set {
        code_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
      }
    }

    /// <summary>Field number for the "Name" field.</summary>
    public const int NameFieldNumber = 2;
    private string name_ = "";
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string Name {
      get { return name_; }
      set {
        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
      }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override bool Equals(object other) {
      return Equals(other as Team);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public bool Equals(Team other) {
      if (ReferenceEquals(other, null)) {
        return false;
      }
      if (ReferenceEquals(other, this)) {
        return true;
      }
      if (Code != other.Code) return false;
      if (Name != other.Name) return false;
      return Equals(_unknownFields, other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override int GetHashCode() {
      int hash = 1;
      if (Code.Length != 0) hash ^= Code.GetHashCode();
      if (Name.Length != 0) hash ^= Name.GetHashCode();
      if (_unknownFields != null) {
        hash ^= _unknownFields.GetHashCode();
      }
      return hash;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override string ToString() {
      return pb::JsonFormatter.ToDiagnosticString(this);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void WriteTo(pb::CodedOutputStream output) {
      if (Code.Length != 0) {
        output.WriteRawTag(10);
        output.WriteString(Code);
      }
      if (Name.Length != 0) {
        output.WriteRawTag(18);
        output.WriteString(Name);
      }
      if (_unknownFields != null) {
        _unknownFields.WriteTo(output);
      }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public int CalculateSize() {
      int size = 0;
      if (Code.Length != 0) {
        size += 1 + pb::CodedOutputStream.ComputeStringSize(Code);
      }
      if (Name.Length != 0) {
        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
      }
      if (_unknownFields != null) {
        size += _unknownFields.CalculateSize();
      }
      return size;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(Team other) {
      if (other == null) {
        return;
      }
      if (other.Code.Length != 0) {
        Code = other.Code;
      }
      if (other.Name.Length != 0) {
        Name = other.Name;
      }
      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(pb::CodedInputStream input) {
      uint tag;
      while ((tag = input.ReadTag()) != 0) {
        switch(tag) {
          default:
            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
            break;
          case 10: {
            Code = input.ReadString();
            break;
          }
          case 18: {
            Name = input.ReadString();
            break;
          }
        }
      }
    }

  }

  public sealed partial class PlayerSearchCondition : pb::IMessage<PlayerSearchCondition> {
    private static readonly pb::MessageParser<PlayerSearchCondition> _parser = new pb::MessageParser<PlayerSearchCondition>(() => new PlayerSearchCondition());
    private pb::UnknownFieldSet _unknownFields;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pb::MessageParser<PlayerSearchCondition> Parser { get { return _parser; } }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public static pbr::MessageDescriptor Descriptor {
      get { return global::mxProject.Examples.PlayerServiceReflection.Descriptor.MessageTypes[2]; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    pbr::MessageDescriptor pb::IMessage.Descriptor {
      get { return Descriptor; }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public PlayerSearchCondition() {
      OnConstruction();
    }

    partial void OnConstruction();

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public PlayerSearchCondition(PlayerSearchCondition other) : this() {
      playerName_ = other.playerName_;
      teamName_ = other.teamName_;
      positions_ = other.positions_;
      _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public PlayerSearchCondition Clone() {
      return new PlayerSearchCondition(this);
    }

    /// <summary>Field number for the "PlayerName" field.</summary>
    public const int PlayerNameFieldNumber = 1;
    private string playerName_ = "";
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string PlayerName {
      get { return playerName_; }
      set {
        playerName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
      }
    }

    /// <summary>Field number for the "TeamName" field.</summary>
    public const int TeamNameFieldNumber = 2;
    private string teamName_ = "";
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public string TeamName {
      get { return teamName_; }
      set {
        teamName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
      }
    }

    /// <summary>Field number for the "Positions" field.</summary>
    public const int PositionsFieldNumber = 3;
    private global::mxProject.Examples.Positions positions_ = 0;
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public global::mxProject.Examples.Positions Positions {
      get { return positions_; }
      set {
        positions_ = value;
      }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override bool Equals(object other) {
      return Equals(other as PlayerSearchCondition);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public bool Equals(PlayerSearchCondition other) {
      if (ReferenceEquals(other, null)) {
        return false;
      }
      if (ReferenceEquals(other, this)) {
        return true;
      }
      if (PlayerName != other.PlayerName) return false;
      if (TeamName != other.TeamName) return false;
      if (Positions != other.Positions) return false;
      return Equals(_unknownFields, other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override int GetHashCode() {
      int hash = 1;
      if (PlayerName.Length != 0) hash ^= PlayerName.GetHashCode();
      if (TeamName.Length != 0) hash ^= TeamName.GetHashCode();
      if (Positions != 0) hash ^= Positions.GetHashCode();
      if (_unknownFields != null) {
        hash ^= _unknownFields.GetHashCode();
      }
      return hash;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public override string ToString() {
      return pb::JsonFormatter.ToDiagnosticString(this);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void WriteTo(pb::CodedOutputStream output) {
      if (PlayerName.Length != 0) {
        output.WriteRawTag(10);
        output.WriteString(PlayerName);
      }
      if (TeamName.Length != 0) {
        output.WriteRawTag(18);
        output.WriteString(TeamName);
      }
      if (Positions != 0) {
        output.WriteRawTag(24);
        output.WriteEnum((int) Positions);
      }
      if (_unknownFields != null) {
        _unknownFields.WriteTo(output);
      }
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public int CalculateSize() {
      int size = 0;
      if (PlayerName.Length != 0) {
        size += 1 + pb::CodedOutputStream.ComputeStringSize(PlayerName);
      }
      if (TeamName.Length != 0) {
        size += 1 + pb::CodedOutputStream.ComputeStringSize(TeamName);
      }
      if (Positions != 0) {
        size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Positions);
      }
      if (_unknownFields != null) {
        size += _unknownFields.CalculateSize();
      }
      return size;
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(PlayerSearchCondition other) {
      if (other == null) {
        return;
      }
      if (other.PlayerName.Length != 0) {
        PlayerName = other.PlayerName;
      }
      if (other.TeamName.Length != 0) {
        TeamName = other.TeamName;
      }
      if (other.Positions != 0) {
        Positions = other.Positions;
      }
      _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
    }

    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
    public void MergeFrom(pb::CodedInputStream input) {
      uint tag;
      while ((tag = input.ReadTag()) != 0) {
        switch(tag) {
          default:
            _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
            break;
          case 10: {
            PlayerName = input.ReadString();
            break;
          }
          case 18: {
            TeamName = input.ReadString();
            break;
          }
          case 24: {
            positions_ = (global::mxProject.Examples.Positions) input.ReadEnum();
            break;
          }
        }
      }
    }

  }

  #endregion

}

#endregion Designer generated code
```




## C# ソースコード（サービス） ##

| 型 | 種類 | 説明 |
|---|---|---|
| PlayerSearch | class | 静的メンバーとサービスクラス・クライアントクラスが定義された静的クラス |
| PlayerSearch.PlayerSearchBase | class | サービスの基底クラス |
| PlayerSearch.PlayerSearchClient | class | クライアントクラス |

* RPCメソッドの引数と戻り値として使用されている各エンティティクラスに対する`Marshaller<T>`型のフィールドが定義されます。`Marshaller<T>`は T に対するシリアライズメソッドとデシリアライズメソッドを持つ型です。別のシリアライザを使用するときにはこの`Marshaller<T>`を置き換えるのですが、残念ながら private static readonly フィールドです。

* `Method<TRequest, TResponse>`型のフィールドが定義されます。これも private static readonly フィールドです。`Method<TRequest, TResponse>`は次の値を持ち、RPCメソッドを呼び出すときのメソッド識別情報として使用されます。
    * RPCメソッドの種類（Unary/ClientStreaming/ServerStreaming/DuplexStreaming）
    * サービス名
    * メソッド名
    * 引数と戻り値に対するマーシャラー（`Marshaller<TRequest>`, `Marshaller<TResponse>`）
    
* proto ファイルを使わずに直接RPCメソッドを実装する場合、この`Method<TRequest, TResponse>`をクライアントサイドとサーバーサイドで共有するように設計することになります。
 
* サービスの基底クラスは、RPCメソッドのスケルトンのみが定義された抽象クラスです。サービスアプリケーションではこのクラスを継承したサービス具象クラスを実装することになります。
 
* クライアントクラスは、RPCメソッドの呼び出しが実装されたクラスです。sealed クラスではないため継承することはできますが、挙動をカスタマイズする場合はこのクラスを継承するのではなく、メソッド呼び出しの主処理を行う`CallInvoker`を継承したほうがよいと思います。なお、RPCメソッドの前後にログ出力を行いたいような目的であればわざわざ`CallInvoker`を継承する必要はなく、`Interceptor`を使ったほうが簡単かつ柔軟です。
[参考【mxProject】gRPC (C#) に追加されたインターセプターの使用方法](https://mxproj.blogspot.com/2018/05/grpc-interceptor.html)
 
#### 生成されたソースコード ####

```c#:PlayerServiceGrpc.cs

// <auto-generated>
//     Generated by the protocol buffer compiler.  DO NOT EDIT!
//     source: PlayerService.proto
// </auto-generated>
#pragma warning disable 0414, 1591
#region Designer generated code

using grpc = global::Grpc.Core;

namespace mxProject.Examples {
  public static partial class PlayerSearch
  {
    static readonly string __ServiceName = "PlayerSearch";

    static readonly grpc::Marshaller<global::mxProject.Examples.PlayerSearchCondition> __Marshaller_PlayerSearchCondition = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::mxProject.Examples.PlayerSearchCondition.Parser.ParseFrom);
    static readonly grpc::Marshaller<global::mxProject.Examples.Player> __Marshaller_Player = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::mxProject.Examples.Player.Parser.ParseFrom);

    static readonly grpc::Method<global::mxProject.Examples.PlayerSearchCondition, global::mxProject.Examples.Player> __Method_SearchPlayer = new grpc::Method<global::mxProject.Examples.PlayerSearchCondition, global::mxProject.Examples.Player>(
        grpc::MethodType.ServerStreaming,
        __ServiceName,
        "SearchPlayer",
        __Marshaller_PlayerSearchCondition,
        __Marshaller_Player);

    /// <summary>Service descriptor</summary>
    public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
    {
      get { return global::mxProject.Examples.PlayerServiceReflection.Descriptor.Services[0]; }
    }

    /// <summary>Base class for server-side implementations of PlayerSearch</summary>
    public abstract partial class PlayerSearchBase
    {
      public virtual global::System.Threading.Tasks.Task SearchPlayer(global::mxProject.Examples.PlayerSearchCondition request, grpc::IServerStreamWriter<global::mxProject.Examples.Player> responseStream, grpc::ServerCallContext context)
      {
        throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
      }

    }

    /// <summary>Client for PlayerSearch</summary>
    public partial class PlayerSearchClient : grpc::ClientBase<PlayerSearchClient>
    {
      /// <summary>Creates a new client for PlayerSearch</summary>
      /// <param name="channel">The channel to use to make remote calls.</param>
      public PlayerSearchClient(grpc::Channel channel) : base(channel)
      {
      }
      /// <summary>Creates a new client for PlayerSearch that uses a custom <c>CallInvoker</c>.</summary>
      /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
      public PlayerSearchClient(grpc::CallInvoker callInvoker) : base(callInvoker)
      {
      }
      /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
      protected PlayerSearchClient() : base()
      {
      }
      /// <summary>Protected constructor to allow creation of configured clients.</summary>
      /// <param name="configuration">The client configuration.</param>
      protected PlayerSearchClient(ClientBaseConfiguration configuration) : base(configuration)
      {
      }

      public virtual grpc::AsyncServerStreamingCall<global::mxProject.Examples.Player> SearchPlayer(global::mxProject.Examples.PlayerSearchCondition request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
      {
        return SearchPlayer(request, new grpc::CallOptions(headers, deadline, cancellationToken));
      }
      public virtual grpc::AsyncServerStreamingCall<global::mxProject.Examples.Player> SearchPlayer(global::mxProject.Examples.PlayerSearchCondition request, grpc::CallOptions options)
      {
        return CallInvoker.AsyncServerStreamingCall(__Method_SearchPlayer, null, options, request);
      }
      /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
      protected override PlayerSearchClient NewInstance(ClientBaseConfiguration configuration)
      {
        return new PlayerSearchClient(configuration);
      }
    }

    /// <summary>Creates service definition that can be registered with a server</summary>
    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
    public static grpc::ServerServiceDefinition BindService(PlayerSearchBase serviceImpl)
    {
      return grpc::ServerServiceDefinition.CreateBuilder()
          .AddMethod(__Method_SearchPlayer, serviceImpl.SearchPlayer).Build();
    }

  }
}
#endregion
```

## 参考リンク ##

[【Qiita】Proto3 Language Guide（和訳）](https://qiita.com/CyLomw/items/9aa4551bd6bb9c0818b6)