DependencyInjection组件实现IOC控制反转(2)
目的:讲解DependencyInjection组件实现IOC的步骤
1、添加Nuget包:Micosoft.Extensions.DependencyInjection
2、创建容器:
//创建容器 ServiceCollection services = new ServiceCollection();
3、注册:把服务注册进容器的过程
有两个概念需要说明下:
服务类型(service type):指用户根据什么类型来获取,服务类型可以时接口,也可以是类,建议使用接口,面向接口编程,更灵活
实现类型(implementation type):指真正实现服务的类到底是什么
注册时,可以服务类型和实现类型一致(两个一样的类),也可以服务类型是接口,实现类型是继承于接口的类
如下:IInterfaceA是一个接口,ImplementA是继承于接口IInterfaceA的类
//服务类型和实现类型一致 services.AddTransient<ImplementA,ImplementA>(); //服务类型和实现类型不一致 services.AddTransient<IInterfaceA, ImplementA>();
当然,注册时还有很多重载方法,比如:AddTransient(Type serviceType,implementationType),AddTransient(Type serviceType),AddTransient<Type serviceType>()等等,自己查看文档就可以了
我上面演示的注册都用了AddTransient只是为了方便说明注册的过程,实际上注册还要关注注册对象的生命周期,有以下三种:
Transient:瞬态,每次获取容器相当与new一个新的对象
Scoped:范围,在一个scope范围内是同个对象
Singleton:单例,在整个应用程序中都是同个对象
public interface IInterfaceA { string Name { get; set; } void DoSomething(); } public class ImplementA : IInterfaceA { string IInterfaceA.Name { get; set; } void IInterfaceA.DoSomething() { Console.WriteLine("我是 ImplementA,继承于IInterfaceA"); } }
static void Main(string[] args) { //创建容器 ServiceCollection services = new ServiceCollection(); //注册 //services.AddTransient<ImplementA>();//注册方式1:直接注册实现类 services.AddTransient<IInterfaceA,ImplementA>();//注册方式2:注册服务类型和对应的实现类,推荐使用 }
4、获取容器中的对象,有两种方式:
1)使用服务定位器(ServiceLocator),使用容器的BuildServiceProvider()方法获取ServiceProvider,通过ServiceProvider以下方法获取服务
T GetService<T>():如果获取不到服务,则返回null
Object GetService(Type serviceType):返回的是Object类型,使用时还需要进行类型转换,一般不用,除了在写框架时,通过反射拿到类型
T GetRequiredService<T>():Required,必须的,如果获取不到服务,则抛异常,
object GetRequiredService(Type serviceType):
IEnumerable<T> GetServices<T>():适用于可能有很多满足条件的服务
IEnumerable<object> GetServices(Type serviceType):
注意,如果容器中注册了同个服务的多个实现类型,那么使用 GetService、GetRequiredService获取服务时,都是获取到最后注入容器的实现类型
//使用服务定位方式获取容器对象 using (ServiceProvider service = services.BuildServiceProvider()) { service.GetRequiredService<IInterfaceA>(); IInterfaceA a= service.GetService<IInterfaceA>(); a.DoSomething(); }
2)通过依赖注入的方式:一般是使用构造函数注入
新建InterfaceB接口以及继承于改接口的类ImplementB:
public interface InterfaceB { public string Name { get; set; } } public class ImplementB : InterfaceB { public string Name { get; set; } public ImplementB() { this.Name = "Sam"; } }
新建InterfaceC接口以及继承于改接口的类ImplementC,ImplementC通过构造器注入获取InterfaceB
public interface InterfaceC { void DoSomething(); } public class ImplementC : InterfaceC { private readonly InterfaceB interfaceB; public ImplementC(InterfaceB interfaceB)//构造注入 { this.interfaceB = interfaceB; } public void DoSomething() { Console.WriteLine($"B is {interfaceB.Name}"); } }
Main函数如下:
static void Main(string[] args) { //创建容器 ServiceCollection services = new ServiceCollection(); //注册 services.AddScoped<InterfaceB, ImplementB>(); services.AddScoped<InterfaceC, ImplementC>(); //使用服务定位方式获取容器对象 using (ServiceProvider service = services.BuildServiceProvider()) { InterfaceC interfaceC = service.GetRequiredService<InterfaceC>(); interfaceC.DoSomething(); } }
输出:

可以看到,ImplementC类通过构造注入了接口InterfaceB,这种方式比使用服务定位器更简单,用户不需要写任何多余的代码
依赖注入有“传染性”:如果一个类是通过依赖注入创建的,那么这个类的构造函数中声明的所有服务类型的参数都会被DI赋值,本身这个类也可以注入到其它的服务中

浙公网安备 33010602011771号