C#でメソッドチェーンをうまく作る方法　前編

# はじめに

この記事は株式会社ラグザイア Advent Calendar 2023 の最終日の記事です。

C#でメソッドチェーンを作る方法をまとめていきたいと思います。
前後編になる予定です。

この方法を使うと、メソッドチェーンを書いている時に[IntelliSense](https://e-words.jp/w/%E3%82%A4%E3%83%B3%E3%83%86%E3%83%AA%E3%82%BB%E3%83%B3%E3%82%B9.html)に適切な候補が表示されるようになります。

前編ではメソッドチェーンを作る時のチュートリアルを書いてます。わかりやすいようにところどころで図説します。

# 手法の説明

## メソッドチェーンとは

メソッドチェーンとは以下の図のようにあるインスタンスのメソッドを呼び出した後、その戻り値が同じインスタンスを返すため、同じメソッドを呼び出せるだけでなく他に定義されているメソッドも呼び出せる仕組みのことを言います。まるで鎖（チェーン）のようにメソッドが連なるから「メソッドチェーン」と呼ばれるのでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4734/a6c7b4fb-0e9b-ad10-f945-9a8d617efc10.png)

ここで呼び出せるメソッドは同じインスタンスを戻り値として返すことで実現できます。図で説明すると、AメソッドとBメソッドとCメソッドは同じインスタンスを返します。

```csharp

class X
{
    X A()
    {
        return this; //または return new X(...);
    }
    
    X B()
    {
        return this; //または return new X(...);
    }
    
    X C()
    {
        return this; //または return new X(...);
    }
}

```

呼び出す時はこんな感じになります。

```csharp

    new X().A().A().A();
    new X().A().A().B();
    new X().A().A().C();
    
    new X().A().B().A();
    new X().A().B().B();
    new X().A().B().C();
    
    new X().A().C().A();
    new X().A().C().B();
    new X().A().C().C();

```

## 分岐先の候補を別々にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4734/c6f02b60-2c5e-4e05-a09b-eae9a75c6682.png)

上の図のようにAメソッドをコールした後にBメソッドをコールすると、次の候補がCメソッドとDメソッドになるコードは以下の通りです。

```csharp
class X
{
    X A()
    {
        return this; //または return new X(...);
    }
    
    Y B()
    {
        return new Y(...);
    }
}

class Y
{
    ? C()
    {
        return new ?(...);
    }
    
    ? D()
    {
        return new ?(...);
    }
}
```

呼び出す時はこんな感じになります。

```csharp

    new X().A().A().A();
    
    new X().A().A().B().C();
    new X().A().A().B().D();
    
    new X().A().B().C();
    new X().A().B().D();

```

## メソッドチェーンを終える時は必ず特定のメソッドを呼び出させる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4734/965073ab-9576-ff54-3088-3d17cec0c94a.png)

メソッドチェーンを終える時に必ず特定のメソッドを呼び出したいことが多々あります。

### 例で説明

#### Buildメソッド

例えば Buildメソッド。様々なライブラリで見かけるので例は一つだけ上げます。単純なメソッドチェーンを構成した後にBuildメソッドを実行することで、メソッドチェーンで設定した設定各種を適用した何かを返すような使い方ですね。

```csharp
namespace K2IB;

:
public static class MauiProgram
{
    private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

    public static MauiApp CreateMauiApp()
    {
        try
        {
            var builder = MauiApp.CreateBuilder();
            return builder
                .UseSkiaSharp(true)
                .UseMauiApp<App>()
                .UseMauiCommunityToolkit()
                .UsePrism(prism => prism
#if WINDOWS10_0_17763_0_OR_GREATER
                .ConfigureModuleCatalog(moduleCatalog =>
                {
                    :
                })
#endif
                .OnAppStart(async navigationService =>
                {
                    :
                })
                .RegisterTypes(containerRegistry =>
                {
                    :
                }))
                .UseBarcodeReader()
                .ConfigureMauiHandlers(h =>
                {
                    :
                })
                .ConfigureFonts(fonts =>
                {
                    :
                }).Build();
        }
        catch (Exception ex)
        {
            Crashes.TrackError(ex);
            throw;
        }
    }

    :
}
```

#### ToSqlメソッド（拙作ライブラリで実装）

私の拙作ライブラリHomuraではSQLクエリビルダを実装しており、同様にメソッドチェーンの仕組みがあります。メソッドチェーンを書いた後、ToSqlメソッドでstring型のSQLクエリ文字列を吐き出すようになっていて、それをADO.NETのDbCommandクラスのCommandTextプロパティにセットするような動作イメージです。

https://github.com/dhq-boiler/Homura/blob/efcb1c71a1415352beb476f150fc033737f95945/Homura/ORM/Dao.cs#L1638-L1640

https://gist.github.com/dhq-boiler/72c26b218d8c593a134ec4330043b2d4#file-dao-cs-L29-L31

### 詳説

上記のようなメソッドチェーンを終える時に必ず特定のメソッドを呼び出したいことがあることがわかってもらえたと思うので、戻って図の内容を実装してみます。

再掲

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4734/965073ab-9576-ff54-3088-3d17cec0c94a.png)

#### 悪い例

以下は悪い例です。

```csharp

class X
{
    Y A()
    {
        return new Y();
    }

    string Finish()
    {
        return "FINISHED!!?";
    }
}

class Y
{
    X B()
    {
        return new X();
    }

    X C()
    {
        return new X();
    }

    X D()
    {
        return new X();
    }
}

```

上のように書くと `new X().Finish();` と書けてしまうので良くありません。

以下の図のようになります。Finishメソッドと終了記号が2箇所に増えてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4734/ce1c1738-058f-5eb1-d494-c2c00d7ed0b2.png)


#### 良い例

```csharp

class X
{
    Y A()
    {
        return new Y();
    }
}

class Y
{
    Z B()
    {
        return new Z();
    }

    Z C()
    {
        return new Z();
    }

    Z D()
    {
        return new Z();
    }
}

class Z : X
{
    string Finish()
    {
        return "FINISHED!!";
    }
}

```

Xクラスを継承したZクラスを用意して、そこにFinishメソッドを実装してあげます。次にYクラスの各メソッドでZクラスのインタンスをnewしたものを返すようにします。

次のように使用できます。

```csharp
new X().A().B().Finish();
new X().A().C().Finish();
new X().A().D().Finish();

new X().A().B().A().B().Finish();
new X().A().B().A().C().Finish();
new X().A().B().A().D().Finish();

new X().A().C().A().B().Finish();
new X().A().C().A().C().Finish();
new X().A().C().A().D().Finish();

new X().A().D().A().B().Finish();
new X().A().D().A().C().Finish();
new X().A().D().A().D().Finish();

new X().A().B().A().B().A().B().Finish();
:
```

# おわりに

C#でメソッドチェーンをうまく作る方法の前編を書きました。

これで基礎的なメソッドチェーンの作り方は学べたと思います。

次のステップとしては、後編を読んで、応用を学んでみるのがおすすめです。