本文示例代码,均采用 .NET 6,具体的代码可以在这个仓库 Articles.DI 中获取。
前面的文章中,我们提及了依赖注入的基本使用。我们使用了简单的案例,注册了IMessageWriter
接口,以及编写了两个实现类MessageWriter
和LoggingMessageWriter
,但是它们二者都只有一个构造函数。如果我们注册服务时,实现类有多个构造函数时,容器该如何选择呢?
如何选择构造函数#
我们可以直接写代码,来模拟这个场景。有一个服务 ExampleService,它有多个构造函数,这些构造函数所需参数的数量有多有少,同时需要的类型也各有不同,具体看下面的代码:
// https://github.com/alva-lin/Articles.DI/tree/master/WorkerService3
public class ExampleService
{
public ExampleService() => Console.WriteLine("空のコンストラクタ");
public ExampleService(AService aService) =>
Console.WriteLine("単一引数のコンストラクタ:AService");
public ExampleService(AService aService, BService bService) =>
Console.WriteLine("二つの引数のコンストラクタ:AService, BService");
public ExampleService(AService aService, CService cService) =>
Console.WriteLine("二つの引数のコンストラクタ:AService, CService");
}
public class AService
{
public AService() => Console.WriteLine("AServiceのインスタンス化");
}
public class BService
{
public BService() => Console.WriteLine("BServiceのインスタンス化");
}
public class CService
{
public CService() => Console.WriteLine("CServiceのインスタンス化");
}
ExampleService
クラスには 4 つのコンストラクタがあり、3 つのサービスに依存しています。サービスを登録する際には、AService
とBService
のみを登録します。
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
services.AddSingleton<ExampleService>();
// 異なる組み合わせを作成するために、以下のコードをコメントアウト(またはコメント解除)して実行結果を確認してください
services.AddSingleton<AService>();
services.AddSingleton<BService>();
// services.AddSingleton<CService>();
})
.Build();
await host.RunAsync();
public class Worker : BackgroundService
{
private readonly ExampleService _exampleService;
// ExampleServiceのインスタンスが注入されていますが、どのコンストラクタが呼び出されているのでしょうか?
public Worker(ExampleService exampleService)
{
_exampleService = exampleService;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// 何も実行しない
}
}
上記のコードの実行結果は次の通りです。
AServiceのインスタンス化
BServiceのインスタンス化
二つの引数のコンストラクタ:AService, BService
結果からわかるように、コンテナはExampleService
クラスをインスタンス化する際に、3 番目のコンストラクタを使用しています。すべてのコンストラクタを比較すると、3 番目と 4 番目のコンストラクタが最も多くのパラメータを必要としていますが、4 番目のコンストラクタはCService
クラスを必要としていますが、このサービスはコンテナに登録されていないため、コンテナは 4 番目のコンストラクタを選