在netcore中如何注入同一个接口的多个实现
netcore中自带了Ioc框架,这也影响了我们的编码习惯,以前都是静态类或者直接new对象,现在有了Ioc框架的支持,我们也不必守旧,应当使用起来,接受这种对象管理方式。使用过java的同仁,都习惯了Spring,感觉离开了Spring就好像失去了灵魂一样。Spring经过多年的沉淀,非常的稳定和灵活,相比之下,netcore中自带的Ioc框架太过轻量,中规中矩的使用还算够用,但是其灵活性的确有待加强。比如属性注入、字段注入、方法参数注入等等,虽然说官方强烈建议使用构造函数注入,并且只提供了构造函数注入,但是我感觉后期肯定会支持更多都注入方法的,并且会结合Attribute提供更为灵活的功能,期望这一天能快点到来!
今天主要讨论其中一个问题,就是如何在netcore中注入同一个接口的多个实现,注册多个实现并不难,关键是如何优雅的取出来。下面我们用代码来说话:
public interface IServiceA
{
string GetStr();
}
public class ImplA1 : IServiceA
{
public string GetStr()
{
return "ImplA1";
}
}
public class ImplA2 : IServiceA
{
public string GetStr()
{
return "ImplA2";
}
}
上面的代码是有一个服务接口IServieA,和两个不同的实现类。如果我们这样注册:
services.AddSingleton<IServiceA>(new ImplA1());
services.AddSingleton<IServiceA>(new ImplA2());
第一种使用方式:
public class HomeController : Controller
{
private readonly IServiceA serviceA;
public HomeController(IServiceA serviceA)
{
this.serviceA = serviceA; //这里注入进来的是最后一个实现,也就是ImplA2
}
public IActionResult Index()
{
return Content(serviceA.GetStr());
}
}
这种方法肯定是不行的,因为只能获取注册的最后一个实现。
第二种使用方式:
public class HomeController : Controller
{
private readonly IServiceA serviceA;
public HomeController(IEnumerable<IServiceA> serviceAList)
{
this.serviceA = serviceAList.First(); //这里注入进来的是一个服务集合
}
public IActionResult Index()
{
return Content(serviceA.GetStr());
}
}
这种方法也不好,需要自己在集合中筛选要想的实现。
其实我们更希望是这样的,注册的时候可以使用一个标识,然后使用Attribute指定标识来获取具体的实现:
services.AddSingleton<IServiceA>("impla1",new ImplA1()); //impla1为该实现在该接口的唯一标识
services.AddSingleton<IServiceA>("impla2",new ImplA2()); //同上
可能会有这么一个Attribute类:
public class IdentifierAttribute : Attribute
{
public IdentifierAttribute(string id)
{
this.Id = id;
}
public string Id { get; set; }
}
然后使用的时候大概是这样:
public HomeController([Identifier("impla1")]IServiceA serviceA)
{
this.serviceA = serviceA; //根据Identifier的指定,这里应该是ImplA1,
}
如果能像Spring中@Autowired注解,注入字段就更好了:
[Autowired]
[Identifier("impla1")]
private readonly IServiceA serviceA;
然而,我们该醒醒了,netcore中自带的Ioc没有提供类似这样的功能,我找了很久也没找到。
作为程序员,我们都要具备一种特质,那就是爱思考,经过思考,我感觉可以使用工厂来解决这个问题。这里只是提供一种思路和实现,有更好的方法大家可以留言讨论。
首先我们定义一个用于存储单例的集合类:
public class SingletonFactory
{
Dictionary<Type, Dictionary<string, object>> serviceDict;
public SingletonFactory()
{
serviceDict = new Dictionary<Type, Dictionary<string, object>>();
}
public TService GetService<TService>(string id) where TService : class
{
var serviceType = typeof(TService);
return GetService<TService>(serviceType, id);
}
public TService GetService<TService>(Type serviceType, string id) where TService : class
{
if (serviceDict.TryGetValue(serviceType, out Dictionary<string, object> implDict))
{
if (implDict.TryGetValue(id, out object service))
{
return service as TService;
}
}
return null;
}
public void AddService<TService>(TService service, string id) where TService : class
{
AddService(typeof(TService), service, id);
}
public void AddService(Type serviceType, object service, string id)
{
if (service != null)
{
if (serviceDict.TryGetValue(serviceType, out Dictionary<string, object> implDict))
{
implDict[id] = service;
}
else
{
implDict = new Dictionary<string, object>();
implDict[id] = service;
serviceDict[serviceType] = implDict;
}
}
}
}
这个类中使用一个嵌套的字典来存储服务类的实现,提供添加服务和获取服务的方法。
有了这样一个类,在netcore自带的Ioc中我们就可以获取更多的控制权了。且看下面代码。
注册服务:
SingletonFactory singletonFactory = new SingletonFactory();
singletonFactory.AddService<IServiceA>(new ImplA1(), "impla1");
singletonFactory.AddService<IServiceA>(new ImplA2(), "impla2");
services.AddSingleton(singletonFactory);
我们把同一个接口的多个实现都加到SingletonFactory中,然后把SingletonFactory注册到Ioc。
使用服务:
private readonly IServiceA serviceA;
public HomeController(SingletonFactory singletonFactory)
{
this.serviceA = singletonFactory.GetService<IServiceA>("impla2"); //使用标识从SingletonFactory获取自己想要的服务实现
}
使用服务的时候我们注入SingletonFactory,然后从SingletonFactory根据标识获取具体的服务实现。
这个方法还算优雅吗?
在netcore中如何注入同一个接口的多个实现的更多相关文章
- SpringBoot JPA 中无法注入 JpaRepository 接口的问题及解决方案
错误: 在Springboot 框架中使用JPA的过程中,怎么来实现数据库操作底层的交互呢?Spring JPA其实已经提供了一套很全面的解决方案,实现对数据库的增.删.查.改只需要继承JPA实现类 ...
- Spring Boot + JPA 多模块项目无法注入 JpaRepository 接口
问题描述 Spring Boot + JPA 多模块项目,启动报异常: nested exception is org.springframework.beans.factory.NoSuchBean ...
- .netcore中的依赖注入
IOC.DI相关概念的理解 1.依赖:简单的讲就是"引用到".例如AccountController.cs引用到IAccountService.cs,那么AccountContro ...
- .NetCore中三种注入方式的思考
该篇内容由个人博客点击跳转同步更新!转载请注明出处! .NetCore彻底诠释了"万物皆可注入"这句话的含义,在.NetCore中到处可见注入的使用.因此core中也提供了三种注入 ...
- 由一个RABBITMQ监听器死循环引出的SPRING中BEAN和MAPPER接口的注入问题
1 @Slf4j 2 @RestController 3 @Component 4 public class VouchersReceiverController implements Message ...
- Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Ocelot+Polly缓存、限流、熔断、降级
相关文章 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Consul服务注册,服务发现 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-网 ...
- .NetCore中的日志(2)集成第三方日志工具
.NetCore中的日志(2)集成第三方日志工具 0x00 在.NetCore的Logging组件中集成NLog 上一篇讨论了.NetCore中日志框架的结构,这一篇讨论一下.NetCore的Logg ...
- .NetCore中的日志(1)日志组件解析
.NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包 ...
- spring容器注入一个接口的两个实现类
spring容器中能拥有两个同种类型的bean吗?我有两个dao类同时实现一个接口,这两个接口注入时报了异常如下. org.springframework.beans.factory.NoSuchBe ...
随机推荐
- pythonic语法
b="$".join(str(x) for x in range(10)) a= 2 if 5<2 else 3 print (a)#a是3
- prim算法,克鲁斯卡尔算法---最小生成树
最小生成树的一个作用,就是求最小花费.要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光 ...
- 2017-2018-2 20155303『网络对抗技术』Exp4:恶意代码分析
2017-2018-2 20155303『网络对抗技术』Exp4:恶意代码分析 --------CONTENTS-------- 一.原理与实践说明 1.实践目标 2.实践内容概述 3.基础问题回答 ...
- ROS 多台计算机联网控制机器人
0. 时间同步 sudo apt-get install chrony 1. ubuntu自带的有openssh-client 可以通过如下指令 ssh username@host 来连接同一局域网内 ...
- c语言的重构、清理与代码分析图形化浏览工具: CScout
网址: https://www.spinellis.gr/cscout/ https://www2.dmst.aueb.gr/dds/cscout/index.html https://github. ...
- navicat报caching_sha2_password异常
使用navicat连接mysql报错(升级到mysql8版本时的错) 解决办法: 通过命令行登录mysql后, 输入: alter user 'root'@'localhost' IDENTIFIED ...
- Ex 6_20 最优二叉搜索树..._第六次作业
假设关键字的总数为n,用c[i,j]表示第i个关键字到第j个关键字的最优二叉查找树的代价,我们的目标是求c[0,n-1].要求c[i,j],首先要从第i个关键字到第j个关键字中选一个出来作为根结点,选 ...
- PYTHON-操作系统基础-2-练习
#===============================================# # 1.简述cpu.内存.硬盘的作用# cpu是人的大脑,负责控制全身和运算# 内存是人的记忆,负责 ...
- OCM_第十天课程:Section5—》数据仓库
注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...
- PHP 将数组的值赋值给一组变量
经常需要将一个字符串分割成一组值,然后赋值给不同的变量. 逐行赋值非常繁琐,于是查了一下 PHP 中是否有类似 python 中 a, b = (a, b) 的操作. 果然有 $info = arra ...