.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.在一个类内部,不通过创建对象的实例而能够获得某个实现了公开接口的对象的引用.这种"需 ...
随机推荐
- Linux 基础-文件权限与属性
一,文件类型 1.1,概述 1.2,正规文件(regular file) 1.3,目录(directory) 1.4,链接文件(link) 1.5,设备与装置文件(device) 1.6,资料接口文件 ...
- jquery 操作样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- CTF中RSA常见类型解法
Python脚本 #十六进制转ASCII编码 import binascii print(binascii.unhexlify(hex(m)[2:])) #rsa import gmpy2 phi = ...
- vba 正则表达式用法
Sub Regexp_test(Sht As String, str As String)On Error Resume NextDim regx As ObjectDim arr, brr, mhS ...
- Karmada多云多集群生产实践专场圆满落幕
摘要:CNCF Karmada社区Cloud Native Days China 2022南京站成功举办. 本文分享自华为云社区<Karmada多云多集群生产实践专场圆满落幕|Cloud Nat ...
- 架构设计(四):CDN
架构设计(四):CDN 作者:Grey 原文地址: 博客园:架构设计(四):CDN CSDN:架构设计(四):CDN CDN 全称 Content delivery network ,即:内容分发网络 ...
- C++11(列表初始化+变量类型推导+类型转换+左右值概念、引用+完美转发和万能应用+定位new+可变参数模板+emplace接口)
列表初始化 用法 在C++98中,{}只能够对数组元素进行统一的列表初始化,但是对应自定义类型,无法使用{}进行初始化,如下所示: // 数组类型 int arr1[] = { 1,2,3,4 }; ...
- JAVA中使用最广泛的本地缓存?Ehcache的自信从何而来2 —— Ehcache的各种项目集成与使用初体验
大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 在上一篇文章<JAVA中使用最广 ...
- python之路52 ORM查询、ORM事务、查询优化、常用字段及参数、ajax方法
Q查询进阶操作 from django.db.models import Q q_obj = Q() # 1.产生q对象 q_obj.connector = 'or' # 默认多个条件的连接是and可 ...
- python之路24之 面向对象动静态方法、继承、派生
昨日内容回顾 人狗大战 1.直接使用字典表示人和狗 p1 = {} p2 = {} p3 = {} p4 = {} 2.封装产生人和狗的函数 def crreate_person():pass def ...