一 概念
依赖注入(Dependency Injection,DI)是控制反转(inversion of Controller,IOC)思想的实现方式。
依赖注入简化模块的组装过程,降低模块之间的耦合度。
生活中的”控制反转“,自己发电——用电网的电
1.代码控制反转的目的:
“怎样创建XX对象”——>“我要XX对象”
两种实现方式:
(1)服务定位器(ServiceLocator);
(2)依赖注入(Dependency Injection,DI);
2.DI几个概念
- 服务:对象;
- 注册服务;
- 服务容器:负责管理注册的服务;
- 查询服务:创建对象及关联对象;
- 对象生命周期:Transient(瞬态)——每次获取都获得新的一个对象,Scoped(范围)——在这个范围之内,每次获取都是同一个对象,Singleton(单例)——无论谁获取的这个服务,拿到都是同一个对象;
3. .NET使用DI
(1).测试代码
using Microsoft.Extensions.DependencyInjection;
using System;
namespace ioc1 // Note: actual namespace depends on the project name.
{
class Program
{
static void Main(string[] args)
{
//普通注册方式
ServiceCollection services = new ServiceCollection();
//添加一个服务
services.AddTransient<TestServiceImpl>();
//服务定位器_Serviceprovider
using (ServiceProvider sp = services.BuildServiceProvider())
{
TestServiceImpl testService = sp.GetRequiredService<TestServiceImpl>();
testService.Name = "tom";
testService.SayHi();
}
}
public interface ITestService
{
public string Name { get; set; }
public void SayHi();
}
public class TestServiceImpl : ITestService
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"Hi, I'm {Name}");
}
}
public class TestServiceImpl2 : ITestService
{
public string Name { get; set; }
public void SayHi()
{
Console.WriteLine($"你好,我是{Name}");
}
}
}
}
(2).根据类型来获取和注册服务
可以分别指定服务类型(Service type)和实现类型(implementation type),这两者可能相同,也可能不同,服务类型可以是类,也可以是接口,建议面向接口编程,更灵活。
(3). .NET控制反转组件取名为DependencyInjection,但它包含ServiceLocator的功能。
(4)如何使用
- Install-Package Microsoft.Extensions.DependencyInjection
- using Microsoft.Extensions.DependencyInjection
- ServiceCollection用来构造容器对象IServiceProvider。
- 调用ServiceCollection的BuildServiceProvider()创建的ServiceProvider,可以用来获取BuildServiceProvider()之前ServiceCollection中的对象。
//普通注册方式
ServiceCollection services = new ServiceCollection();
services.AddTransient<TestServiceImpl>();
//服务定位器
using (ServiceProvider sp = services.BuildServiceProvider())
{
TestServiceImpl testService = sp.GetRequiredService<TestServiceImpl>();
testService.Name = "tom";
testService.SayHi();
}
4.生命周期
- 给类构造函数中打印,看看不同生命周期的对象创建,使用serviceProvider.CreateScope()创建Scope。
- 如果一个类实现了IDisposable接口,则离开作用域之后容器会自动调用对象的Dispose方法。
- 不要再长生命周期的对象中引用比它短的生命周期的对象,在ASP.NET Core中,这样做默认会抛出异常。
- 生命周期的选择,如果类无状态,建议为Singleton;如果类有状态,且有Scope控制,建议为Scoped,因为通常这种scope控制下的代码都是运行在同一线程中的,没有并发修改的问题,在使用Transient的时候要谨慎。
- .NET注册服务的重载方法有很多。