.NET MAUIを例に、なんとなくBuilderを分かっている状態から自分でBuilderを拡張できる状態にする

# .NET MAUIを例に、なんとなくBuilderを分かっている状態から自分でBuilderを拡張できる状態にする

## はじめに

最近 [.NET MAUI](https://github.com/dotnet/maui) に興味を持ち、ライブラリでカメラを使ってみたり、お絵描きしてみたりなどお試しで触ってます）。
MAUIプログラムでソリューションを新規に作成するとMauiProgramクラスができるのですが、以下のような一見謎のコードができます。

```cs
	public static MauiApp CreateMauiApp()
	{
		var builder = MauiApp.CreateBuilder();
		builder
			.UseMauiApp<App>()
			.ConfigureFonts(fonts =>
			{
				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
			});

		return builder.Build();
	}
```

もちろん引数名の通り、デザインパターンのひとつであるBuilderパターンに則った実装であることは推測できるわけですが、このコードにたった1行加えると（具体的には、自分の場合はSkiaSharpでした）ライブラリを使う準備が整います。

```cs
	public static MauiApp CreateMauiApp()
	{
		var builder = MauiApp.CreateBuilder();
		builder
			.UseSkiaSharp(true) // この行を増やしただけ！
			.UseMauiApp<App>()
			.ConfigureFonts(fonts =>
			{
				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
			});

		return builder.Build();
	}
```

本記事ではその内部ではどのようなことをしているのか、OSSを読んで理解することで実感してBuilderを拡張できるようにしたい、という目的の記事となっています。

## 詳細

今回は上記で利用しましたSkiaSharpを題材に、その中身を見ようと思います。
最新のコードは[リンク先](https://github.com/mono/SkiaSharp/blob/main/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs)の通りですが、筆者が確認した当時のコードは以下の通りとなっています。

```cs
using System;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using SkiaSharp.Views.Maui.Controls.Hosting;
using SkiaSharp.Views.Maui.Handlers;

namespace SkiaSharp.Views.Maui.Controls
{
	[Obsolete("Use SkiaSharp.Views.Maui.Controls.Hosting instead.", true)]
	public static class AppHostBuilderExtensions
	{
		[Obsolete("Use SkiaSharp.Views.Maui.Controls.Hosting.UseSkiaSharp() instead.", true)]
		public static MauiAppBuilder UseSkiaSharpHandlers(this MauiAppBuilder builder) => builder.UseSkiaSharp();
	}
}

namespace SkiaSharp.Views.Maui.Controls.Hosting
{
	public static class AppHostBuilderExtensions
	{
		public static MauiAppBuilder UseSkiaSharp(this MauiAppBuilder builder) =>
			builder
				.ConfigureMauiHandlers(handlers =>
				{
					handlers.AddHandler<SKCanvasView, SKCanvasViewHandler>();
				})
				.ConfigureImageSources(sources =>
				{
					sources.AddService<ISKImageImageSource, SKImageSourceService>();
					sources.AddService<ISKBitmapImageSource, SKImageSourceService>();
					sources.AddService<ISKPixmapImageSource, SKImageSourceService>();
					sources.AddService<ISKPictureImageSource, SKImageSourceService>();
				});
	}
}
```

上記、一部名前空間を変更する前の名残がありますが、本体処理はかなりシンプルです。

- 拡張メソッドを利用してMauiAppBuilderのメソッドを増やす
- MauiAppBuilderの公開するメソッドを利用してハンドラおよびサービスを登録する

この一工夫で利用者側はかなり楽して利用することができます。

とすると、MauiAppBuilderのメソッドさえ理解できていれば、そのBuilderを利用するライブラリ開発者としてはその準備が簡単に整えられるということになります。
ただ、MauiAppBuilderのメソッド一覧の説明がないか少し探してみたのですが、あまり簡単にはみつかりませんでした（個別記事で紹介されているのは[一部](https://learn.microsoft.com/ja-jp/dotnet/maui/user-interface/fonts)見つけました）。
そのため、インテリセンスでメソッド一覧を出して、実際に何がどんなふうに使えるかみるのが一番手っ取り早そうです。
あるいは、[ここ](https://github.com/dotnet/maui/blob/main/src/Core/src/Hosting/MauiAppBuilder.cs#L22)でデフォルトで利用するときのメソッド呼び出しがなされているため、どのようなサービスが登録されているかを確認してみるのもありかもしれません。

（参考）MauiAppBuilderに登録することで、依存性注入できるという嬉しさも享受できます。詳細は以下のリンクにあります。
<https://learn.microsoft.com/en-us/dotnet/architecture/maui/dependency-injection>

## おわりに

実際に.NET MAUIを例にとって、Builderパターンを用いて拡張することが簡単であることが分かりました。
必要なのは以下の2ステップです。

- MauiAppBuilderの拡張メソッドを追加する
- 拡張メソッド内で利用したいハンドラやサービスなどを登録する
  - 利用イメージがつかない場合は、[ここ](https://github.com/dotnet/maui/blob/main/src/Core/src/Hosting/MauiAppBuilder.cs#L22)でデフォルトで利用するときの実際の中身を見てみるとよさそう

また気になることがあれば、調べてみようと思います。
誰かの参考になれば幸いです。