依存性注入(DI:Dependency Injection)は、ソフトウェア開発においてコンポーネント間の結合度を下げ、テストやメンテナンスを容易にするための重要なデザインパターンです。C#と.NET 8を用いたコンソールアプリケーションでの「依存性注入」の実装について説明します。
依存性注入コンテナの設定
.NET Core
および .NET5
以降では、Microsoft.Extensions.DependencyInjection
を使用して依存性注入をサポートします。これにより、アプリケーションの様々な部分で必要とされる依存関係を管理しやすくなります。
var services = new ServiceCollection();
ConfigureServices(services);
ServiceCollection
クラスを使用して依存性注入コンテナを初期化し、アプリケーションで使用するサービスを登録します。
サービスの登録
依存性注入を利用するには、サービス(この場合はリポジトリ)をコンテナに登録する必要があります。これにより、インターフェースとその実装間の関連付けが行われます。
private static void ConfigureServices(ServiceCollection services)
{
services.AddTransient<IUserRepository, UserRepository>();
}
ここでは、IUserRepository
インターフェースとその実装である UserRepository
をトランジェント(毎回新しいインスタンスを生成)スコープで登録しています。これにより、IUserRepository
が要求されるたびに UserRepository
の新しいインスタンスが提供されます。
サービスプロバイダのビルドとサービスの取得
サービスプロバイダをビルドし、登録したサービスを取得して利用します。
using (var serviceProvider = services.BuildServiceProvider())
{
var userRepository = serviceProvider.GetRequiredService<IUserRepository>();
...
}
BuildServiceProvider
を呼び出すことで、サービスプロバイダをビルドします。そして、GetRequiredService
を使用して、IUserRepository
インターフェースの実装を取得し、利用します。
サービスの利用
取得したサービス(この場合はリポジトリ)を使用して、ビジネスロジック(ユーザーの保存や検索など)を実行します。
var user = new User(new UserId("T001"), new UserName("Tom"));
userRepository.Save(user);
var head = userRepository.Find(user.Name);
Console.WriteLine(head.Name.Value);
ここでの例では、ユーザーを作成し、リポジトリを通じて保存後、同じリポジトリを使って検索を行い、結果をコンソールに出力しています。
コード全文
using ConsoleApp.Classes.Models;
using ConsoleApp.Classes.Repositories.Implementations;
using ConsoleApp.Classes.Repositories.Interfaces;
using Microsoft.Extensions.DependencyInjection;
class Program
{
public static void Main(string[] args)
{
var services = new ServiceCollection();
ConfigureServices(services);
using (var serviceProvider = services.BuildServiceProvider())
{
var userRepository = serviceProvider.GetRequiredService<IUserRepository>();
var user = new User(
new UserId("T001"),
new UserName("Tom")
);
userRepository.Save(user);
var head = userRepository.Find(user.Name);
Console.WriteLine(head.Name.Value);
}
}
private static void ConfigureServices(ServiceCollection services)
{
services.AddTransient<IUserRepository, UserRepository>();
}
}
まとめ
依存性注入を適切に利用することで、コンポーネント間の結合度を下げ、アプリケーションのテストやメンテナンスを容易にすることが可能です。