前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET依赖注入之一个接口多个实现

.NET依赖注入之一个接口多个实现

作者头像
郑子铭
发布2023-08-29 10:11:16
2700
发布2023-08-29 10:11:16
举报
文章被收录于专栏:DotNet NB && CloudNative

前言

最近又在项目中碰到需要将原本单实现的接口改造成多个实现的场景,这里记录一下常见的几种改法。

假设已经存在如下接口ICustomService和其实现CustomService,由于只有一种实现,注入和使用非常容易。

代码语言:javascript
复制
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内的方法移到到一个新的基接口,共享出来,需要多少个实现,就创建多少个空接口继承该基接口。

代码语言:javascript
复制
//基接口
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;
}

这种实现方式需要增加了一套空接口做隔离,看似可能比较“浪费”,但后期随着项目的演进,ICustomServiceICustomServiceV2可能会慢慢分化,我们可以很方便的为它们扩充各种独有方法。

使用单接口实现

如果我们确定不需要多个接口,也可以使用下面的单接口实现

代码语言:javascript
复制
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);
}

从上面代码可以看到,我们是为从接口ICustomService注册两个实现,并从IEnumerable<ICustomService>解析出了这两个实现。这里可能会有两个疑问

  1. 为什么第一个实现CustomService没有被第二个实现CustomServiceV2替换掉?
  2. 为什么可以从IEnumerable<ICustomService>解析到我们需要的服务?

答案在Microsoft.Extensions.DependencyInjection.ServiceDescriptor 和 Microsoft.Extensions.DependencyInjection.ServiceCollection 这两个类里,进程里,依赖注入的服务,会被添加到ServiceCollection里,ServiceCollection是一组ServiceDescriptor的集合,ServiceDescriptor通过服务类型、实现以及生命周期三个组合在一起构成的标识来确定服务。而ICustomService+CustomService+TransientICustomService+CustomServiceV2+Transient是两个不同的ServiceDescriptor,因此不会被替换。同时服务类型的ServiceDescriptor会被聚合在一起,于是我们可以很方便的从IEnumerable对象中解析出所有的同类型的服务。

总结

本质上,两种方法都是多态性(Polymorphism)的应用,没有优劣之分,根据场景选择合适的写法。

链接

https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection https://github.com/dotnet/runtime

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 使用多个接口实现
  • 使用单接口实现
  • 总结
  • 链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档