最近又在项目中碰到需要将原本单实现的接口改造成多个实现的场景,这里记录一下常见的几种改法。
假设已经存在如下接口ICustomService和其实现CustomService,由于只有一种实现,注入和使用非常容易。
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;}
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;}
//基接口
public interface ICustomBaseService
//多个空接口
public interface ICustomService : ICustomBaseService
public interface ICustomServiceV2 : ICustomBaseService
//第一种实现
//第二种实现
public class CustomServiceV2: ICustomServiceV2
builder.Services.AddTransient<ICustomServiceV2, CustomServiceV2>();
private readonly ICustomServiceV2 _customServiceV2;
public CustomController(ICustomService customService,ICustomServiceV2 customServiceV2)
_customServiceV2 = customServiceV2;
这种实现方式需要增加了一套空接口做隔离,看似可能比较“浪费”,但后期随着项目的演进,ICustomService和ICustomServiceV2可能会慢慢分化,我们可以很方便的为它们扩充各种独有方法。
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 ICustomService _customServiceV2;public CustomController(IEnumerable<ICustomService> customServices){ _customService = customServices.ElementAt(0); _customServiceV2 = customServices.ElementAt(1);}
public class CustomServiceV2: ICustomService
builder.Services.AddTransient<ICustomService, CustomServiceV2>();
private readonly ICustomService _customServiceV2;
public CustomController(IEnumerable<ICustomService> customServices)
_customService = customServices.ElementAt(0);
_customServiceV2 = customServices.ElementAt(1);
从上面代码可以看到,我们是为从接口ICustomService注册两个实现,并从IEnumerable<ICustomService>解析出了这两个实现。这里可能会有两个疑问
IEnumerable<ICustomService>
CustomServiceV2
答案在Microsoft.Extensions.DependencyInjection.ServiceDescriptor 和 Microsoft.Extensions.DependencyInjection.ServiceCollection 这两个类里,进程里,依赖注入的服务,会被添加到ServiceCollection里,ServiceCollection是一组ServiceDescriptor的集合,ServiceDescriptor通过服务类型、实现以及生命周期三个组合在一起构成的标识来确定服务。而ICustomService+CustomService+Transient和ICustomService+CustomServiceV2+Transient是两个不同的ServiceDescriptor,因此不会被替换。同时服务类型的ServiceDescriptor会被聚合在一起,于是我们可以很方便的从IEnumerable对象中解析出所有的同类型的服务。
ServiceCollection
ServiceDescriptor
ICustomService+CustomService+Transient
ICustomService+CustomServiceV2+Transient
本质上,两种方法都是多态性(Polymorphism)的应用,没有优劣之分,根据场景选择合适的写法。
https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection https://github.com/dotnet/runtime
作者: 几秋
出处: https://www.cnblogs.com/netry/p/net-dependency-injection-multiple-implementations.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
原文链接:https://www.cnblogs.com/netry/p/net-dependency-injection-multiple-implementations.html
本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728