我们在使用Microsoft.Extensions.DependencyInjection进行构造方法依赖注入时,可以注入IServiceProvider接口的实例,然后可以用这个实例来获取其它依赖注入的类。
下面的示例代码中,我们定义了IPeople接口和实现类People,是一组依赖注入关系。还定义了IPeopleService接口和实现类PeopleService,也是一组依赖注入关系,在PeopleService类的构造方法中首先注入了IPeople接口示例,还注入了IServiceProvider的接口实例,然后在PeopleService类CreatePeople方法中,来使用IServiceProvider接口的实例来获取其它依赖注入的类。
using Microsoft.Extensions.DependencyInjection;namespace Net8DependencyInjection {interface IPeople{string? Name{get;set;}}class People : IPeople{private string? _name;public string? Name{get{return _name;}set{_name = value;}}}interface IPeopleService{IServiceProvider GetCurrentServiceProvider();IPeople? CreatePeople();}class PeopleService : IPeopleService, IDisposable{protected IServiceProvider _serviceProvider;protected IPeople _people;//因为PeopleService类由依赖注入DI创建,所以依赖注入DI可以给PeopleService类的构造方法注入IServiceProvider接口的实例,可以用它来获取其它依赖注入的类public PeopleService(IPeople people, IServiceProvider serviceProvider){_people = people;_serviceProvider = serviceProvider;}//用PeopleService类的构造方法注入的IServiceProvider接口实例,来获取其它依赖注入的类public IPeople? CreatePeople(){return _serviceProvider.GetService<IPeople>();}public void Dispose(){if (_serviceProvider is IDisposable){Console.WriteLine("Disposing _serviceProvider ...");IDisposable disposable = (IDisposable)_serviceProvider;disposable.Dispose();}}//返回构造方法中依赖注入的IServiceProvider接口实例public IServiceProvider GetCurrentServiceProvider(){return _serviceProvider;}}internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddTransient<IPeople, People>(); //注册IPeople接口和People类的依赖注入关系services.AddTransient<IPeopleService, PeopleService>(); //注册IPeopleService接口和PeopleService类的依赖注入关系using (ServiceProvider rootServiceProvider = services.BuildServiceProvider()){IPeopleService? rootPeopleService = rootServiceProvider.GetService<IPeopleService>();IPeople? peopleInRoot = rootPeopleService?.CreatePeople();peopleInRoot!.Name = "Jack";Console.WriteLine("rootPeopleService.GetCurrentServiceProvider is {0}", rootPeopleService?.GetCurrentServiceProvider().GetType().ToString()); //rootPeopleService.GetCurrentServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScopeConsole.WriteLine("rootServiceProvider is {0}", rootServiceProvider.GetType().ToString()); //rootServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceProviderConsole.WriteLine("rootPeopleService.GetCurrentServiceProvider == rootServiceProvider is {0}", rootPeopleService?.GetCurrentServiceProvider() == rootServiceProvider); //rootPeopleService.GetCurrentServiceProvider == rootServiceProvider is False Console.WriteLine();Console.WriteLine();Console.WriteLine();using (IServiceScope serviceScope = rootServiceProvider.CreateScope()){IPeopleService? scopePeopleService = serviceScope.ServiceProvider.GetService<IPeopleService>();IPeople? peopleInScope = scopePeopleService?.CreatePeople();peopleInScope!.Name = "Tom";Console.WriteLine("peopleInRoot == peopleInScope is {0}", peopleInRoot == peopleInScope); //peopleInRoot == peopleInScope is FalseConsole.WriteLine("scopePeopleService.GetCurrentServiceProvider is {0}", scopePeopleService?.GetCurrentServiceProvider().GetType().ToString()); //scopePeopleService.GetCurrentServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScopeConsole.WriteLine("serviceScope.ServiceProvider is {0}", serviceScope.ServiceProvider.GetType().ToString()); //serviceScope.ServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScopeConsole.WriteLine("scopePeopleService.GetCurrentServiceProvider == serviceScope.ServiceProvider is {0}", scopePeopleService?.GetCurrentServiceProvider() == serviceScope.ServiceProvider); //scopePeopleService.GetCurrentServiceProvider == serviceScope.ServiceProvider is TrueConsole.WriteLine("rootPeopleService.GetCurrentServiceProvider == serviceScope.ServiceProvider is {0}", rootPeopleService?.GetCurrentServiceProvider() == serviceScope.ServiceProvider); //rootPeopleService.GetCurrentServiceProvider == serviceScope.ServiceProvider is False }}Console.WriteLine("Press any key to end...");Console.ReadLine();}} }
上面的代码运行后,输出的结果如下所示:
rootPeopleService.GetCurrentServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope rootServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceProvider rootPeopleService.GetCurrentServiceProvider == rootServiceProvider is FalsepeopleInRoot == peopleInScope is False scopePeopleService.GetCurrentServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope serviceScope.ServiceProvider is Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope scopePeopleService.GetCurrentServiceProvider == serviceScope.ServiceProvider is True rootPeopleService.GetCurrentServiceProvider == serviceScope.ServiceProvider is False Disposing _serviceProvider ... Disposing _serviceProvider ... Press any key to end...
下面的这篇微软官方文档,还提到Microsoft.Extensions.DependencyInjection在使用依赖注入调用类的构造方法创建实例时,构造方法中可以包含非依赖注入关系的参数,但是这种参数必须要有默认值,否则会报错:
Constructor injection behavior
Constructors can accept arguments that aren't provided by dependency injection, but the arguments must assign default values.