.NET依赖注入之一个接口多个实现
前言
最近又在项目中碰到需要将原本单实现的接口改造成多个实现的场景,这里记录一下常见的几种改法。
假设已经存在如下接口ICustomService和其实现CustomService,由于只有一种实现,注入和使用非常容易。
public interface ICustomService
{
void MethodA();
void MethodB();
}
public class CustomService: ICustomService
{
public void MethodA()
{
}
public void MethodB()
{
}
}
//注入
builder.Services.AddTransient<ICustomService, CustomService>();
//使用
private readonly ICustomService _customService;
public CustomController(ICustomService customService)
{
_customService = customService;
}
现在我们需要增加一种实现。
使用多个接口实现
我们可以将原ICustomService内的方法移到到一个新的基接口,共享出来,需要多少个实现,就创建多少个空接口继承该基接口。
//基接口
public interface ICustomBaseService
{
void MethodA();
void MethodB();
}
//多个空接口
public interface ICustomService : ICustomBaseService
{
}
public interface ICustomServiceV2 : ICustomBaseService
{
}
//第一种实现
public class CustomService: ICustomService
{
public void MethodA()
{
}
public void MethodB()
{
}
}
//第二种实现
public class CustomServiceV2: ICustomServiceV2
{
public void MethodA()
{
}
public void MethodB()
{
}
}
//注入
builder.Services.AddTransient<ICustomService, CustomService>();
builder.Services.AddTransient<ICustomServiceV2, CustomServiceV2>();
//使用
private readonly ICustomService _customService;
private readonly ICustomServiceV2 _customServiceV2;
public CustomController(ICustomService customService,ICustomServiceV2 customServiceV2)
{
_customService = customService;
_customServiceV2 = customServiceV2;
}
这种实现方式需要增加了一套空接口做隔离,看似可能比较“浪费”,但后期随着项目的演进,ICustomService和ICustomServiceV2可能会慢慢分化,我们可以很方便的为它们扩充各种独有方法。
使用单接口实现
如果我们确定不要要多个接口,也可以使用下面的单接口实现
public interface ICustomService
{
void MethodA();
void MethodB();
}
//第一种实现
public class CustomService: ICustomService
{
public void MethodA()
{
}
public void MethodB()
{
}
}
//第二种实现
public class CustomServiceV2: ICustomService
{
public void MethodA()
{
}
public void MethodB()
{
}
}
//注入
builder.Services.AddTransient<ICustomService, CustomService>();
builder.Services.AddTransient<ICustomService, CustomServiceV2>();
//使用
private readonly ICustomService _customService;
private readonly ICustomServiceV2 _customServiceV2;
public CustomController(IEnumerable<ICustomService> customServices)
{
_customService = customServices.ElementAt(0);
_customServiceV2 = customServices.ElementAt(1);
}
从上面代码可以看到,我们是为从接口ICustomService注册两个实现,并从IEnumerable<ICustomService>解析出了这两个实现。这里可能会有两个疑问
- 为什么第一个实现
CustomService没有被第二个实现CustomServiceV2替换掉? - 为什么可以从
IEnumerable<ICustomService>解析到我们需要的服务?
答案在Microsoft.Extensions.DependencyInjection.ServiceDescriptor 和 Microsoft.Extensions.DependencyInjection.ServiceCollection 这两个类里,进程里,依赖注入的服务,会被添加到ServiceCollection里,ServiceCollection是一组ServiceDescriptor的集合,ServiceDescriptor通过服务类型、实现以及生命周期三个组合在一起构成的标识来确定服务。而ICustomService+CustomService+Transient和ICustomService+CustomServiceV2+Transient是两个不同的ServiceDescriptor,因此不会被替换。同时服务类型的ServiceDescriptor会被聚合在一起,于是我们可以很方便的从IEnumerable对象中解析出所有的同类型的服务。
总结
本质上,两种方法都是多态性(Polymorphism)的应用,没有优劣之分,根据场景选择合适的写法。
链接
https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection
https://github.com/dotnet/runtime
.NET依赖注入之一个接口多个实现的更多相关文章
- DDD实战8_2 利用Unity依赖注入,实现接口对应实现类的可配置
1.在Util类库下新建DIService类 /// <summary> /// 创建一个类,对应在配置文件中配置的DIServices里面的对象的 key /// </summar ...
- JUnit5依赖注入与测试接口
依赖注入 以前的JUnit的类构造方法和测试方法都是不能有参数的,JUnit Jupiter有一个颠覆性的改进,就是允许它们有入参,这样就能做依赖注入了. 如果你对pytest的fixture有了解的 ...
- 解读ASP.NET 5 & MVC6系列(7):依赖注入
在前面的章节(Middleware章节)中,我们提到了依赖注入功能(Dependency Injection),ASP.NET 5正式将依赖注入进行了全功能的实现,以便开发人员能够开发更具弹性的组件程 ...
- 不用Unity库,自己实现.NET轻量级依赖注入
在面向对象的设计中,依赖注入(IoC)作为一种重要的设计模式,主要用于削减计算机程序的耦合问题,相对于Java中的Spring框架来说,微软企业库中的Unity框架是目前.NET平台中运用比较广泛的依 ...
- MVC3+AutoFac实现程序集级别的依赖注入
1.介绍 所谓程序集级别的依赖注入是指接口和实现的依赖不使用配置文件或硬代码实现(builder.RegisterType<UserInfoService>().As<IU ...
- [Castle Windsor]学习依赖注入
初次尝试使用Castle Windsor实现依赖注入DI,或者叫做控制反转IOC. 参考: https://github.com/castleproject/Windsor/blob/master/d ...
- Java Web系列:Spring依赖注入基础
一.Spring简介 1.Spring简化Java开发 Spring Framework是一个应用框架,框架一般是半成品,我们在框架的基础上可以不用每个项目自己实现架构.基础设施和常用功能性组件,而是 ...
- [转]解读ASP.NET 5 & MVC6系列(7):依赖注入
本文转自:http://www.cnblogs.com/TomXu/p/4496440.html 在前面的章节(Middleware章节)中,我们提到了依赖注入功能(Dependency Inject ...
- IOC容器的依赖注入
1.依赖注入发生的时间 当Spring IoC容器完成了Bean定义资源的定位.载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入 ...
- 【ASP.NET MVC 学习笔记】- 04 依赖注入(DI)
本文参考:http://www.cnblogs.com/willick/p/3223042.html 1.在一个类内部,不通过创建对象的实例而能够获得某个实现了公开接口的对象的引用.这种"需 ...
随机推荐
- Vue3 企业级优雅实战 - 组件库框架 - 8 搭建组件库 cli
前面的文章分享了组件库的开发.example.组件库文档,本文分享组件库 cli 开发. 1 为什么要开发组件库 cli 回顾一个新组件的完整开发步骤: 1 在 packages 目录下创建组件目录 ...
- day36-ThreadLocal
ThreadLocal 线程数据共享和安全 1.什么是ThreadLocal? ThreadLocal的作用,可以实现在同一个线程数据共享,从而解决多线程数据安全问题 当http请求发送到Tomcat ...
- 用Dockerfile制作一个java应用镜像,ubuntu基础篇
内容介绍: (1) 本章目的,将一个自行开发的java程序webpay-api,制作为docker自定义镜像,并且进行部署. (2) 实验环境: 物理机:VMware 虚拟机 + CentOS 7.8 ...
- (8)go-micro微服务Mysql配置
目录 一 gorm介绍 二 gorm安装 1.1 下载依赖 1.2 使用MySQL驱动 三 CURD操作 1. 查询 1.1 单行查询 1.2 多行查询 2. 插入数据 3. 更新数据 4. 删除数据 ...
- SQL29 计算用户的平均次日留存率
SQL29 计算用户的平均次日留存率 困难 通过率:48.58% 时间限制:1秒 空间限制:256M 描述 题目:现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率.请你取出相应数据. 示例 ...
- strapi系列-如何创建一个定时任务-Cron Jobs
Cron 是什么? Cron 有多种用途. Cron Jobs 用于安排服务器上的任务运行.它们最常用于自动化系统管理或维护.然而,它们也与 Web 应用程序的构建相关. Web 应用程序可能需要在各 ...
- Entrypoint undefined = index.html html-webpack-plugin 错误ERROR in Error: Child compilation failed: Module build failed (from ./node_modules/html-webpack-plu SyntaxError: Unexpected token )
Entrypoint undefined = index.html html-webpack-plugin 错误 ERROR in Error: Child compilation failed: M ...
- Git + Jenkins 自动化 NGINX 发布简易实现
概述 之前基于 GitLab + Jenkins 实现了简单的 NGINX 的自动化发布. 具体包含如下的组件: GitLab 包括 GItLab 的 WebHook: Jenkins 及其插件: G ...
- 如何使用MASA.Blazor
MASA.Blazor 是什么? 基于Material Design设计和BlazorComponent的交互能力提供标准的基础组件库.提供如布局.弹框标准.Loading.全局异常处理等标准场景的预 ...
- MATLAB实现随机森林(RF)回归与自变量影响程度分析
本文介绍基于MATLAB,利用随机森林(RF)算法实现回归预测,以及自变量重要性排序的操作. 目录 1 分解代码 1.1 最优叶子节点数与树数确定 1.2 循环准备 1.3 数据划分 1.4 随机 ...